@ottocode/server 0.1.234 → 0.1.235
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/routes/config/utils.ts +3 -15
- 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 +1 -48
- 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 +5 -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 +8 -21
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
type ProviderId,
|
|
13
13
|
type ReasoningLevel,
|
|
14
14
|
} from '@ottocode/sdk';
|
|
15
|
-
import { debugLog } from '../debug/index.ts';
|
|
16
15
|
import { isCompactCommand, buildCompactionContext } from './compaction.ts';
|
|
17
16
|
import { detectOAuth, adaptSimpleCall } from '../provider/oauth-adapter.ts';
|
|
18
17
|
|
|
@@ -59,10 +58,6 @@ export async function dispatchAssistantMessage(
|
|
|
59
58
|
files,
|
|
60
59
|
} = options;
|
|
61
60
|
|
|
62
|
-
debugLog(
|
|
63
|
-
`[MESSAGE_SERVICE] dispatchAssistantMessage called with userContext: ${userContext ? `${userContext.substring(0, 50)}...` : 'NONE'}`,
|
|
64
|
-
);
|
|
65
|
-
|
|
66
61
|
const sessionId = session.id;
|
|
67
62
|
const now = Date.now();
|
|
68
63
|
const userMessageId = crypto.randomUUID();
|
|
@@ -163,15 +158,10 @@ export async function dispatchAssistantMessage(
|
|
|
163
158
|
},
|
|
164
159
|
});
|
|
165
160
|
|
|
166
|
-
debugLog(
|
|
167
|
-
`[MESSAGE_SERVICE] Enqueuing assistant run with userContext: ${userContext ? `${userContext.substring(0, 50)}...` : 'NONE'}`,
|
|
168
|
-
);
|
|
169
|
-
|
|
170
161
|
const isCompact = isCompactCommand(content);
|
|
171
162
|
let compactionContext: string | undefined;
|
|
172
163
|
|
|
173
164
|
if (isCompact) {
|
|
174
|
-
debugLog('[MESSAGE_SERVICE] Detected /compact command, building context');
|
|
175
165
|
const { getModelLimits } = await import('./compaction.ts');
|
|
176
166
|
const limits = getModelLimits(provider, model);
|
|
177
167
|
const contextTokenLimit = limits
|
|
@@ -182,9 +172,6 @@ export async function dispatchAssistantMessage(
|
|
|
182
172
|
sessionId,
|
|
183
173
|
contextTokenLimit,
|
|
184
174
|
);
|
|
185
|
-
debugLog(
|
|
186
|
-
`[message-service] /compact context length: ${compactionContext.length}, limit: ${contextTokenLimit} tokens`,
|
|
187
|
-
);
|
|
188
175
|
}
|
|
189
176
|
|
|
190
177
|
const toolApprovalMode = cfg.defaults.toolApproval ?? 'dangerous';
|
|
@@ -249,9 +236,7 @@ function scheduleSessionTitle(args: {
|
|
|
249
236
|
titlePending.delete(sessionId);
|
|
250
237
|
try {
|
|
251
238
|
await generateSessionTitle({ cfg, db, sessionId, content });
|
|
252
|
-
} catch
|
|
253
|
-
debugLog('[TITLE_GEN] Title generation error:');
|
|
254
|
-
debugLog(err);
|
|
239
|
+
} catch {
|
|
255
240
|
} finally {
|
|
256
241
|
titleInFlight.delete(sessionId);
|
|
257
242
|
titleActiveCount--;
|
|
@@ -288,34 +273,24 @@ async function generateSessionTitle(args: {
|
|
|
288
273
|
.where(eq(sessions.id, sessionId));
|
|
289
274
|
|
|
290
275
|
if (!existingSession.length) {
|
|
291
|
-
debugLog('[TITLE_GEN] Session not found, aborting');
|
|
292
276
|
return;
|
|
293
277
|
}
|
|
294
278
|
|
|
295
279
|
const sess = existingSession[0];
|
|
296
280
|
if (sess.title && sess.title !== 'New Session') {
|
|
297
|
-
debugLog('[TITLE_GEN] Session already has a title, skipping');
|
|
298
281
|
return;
|
|
299
282
|
}
|
|
300
283
|
|
|
301
284
|
const provider = (sess.provider ?? cfg.defaults.provider) as ProviderId;
|
|
302
285
|
const modelName = sess.model ?? cfg.defaults.model;
|
|
303
286
|
|
|
304
|
-
debugLog('[TITLE_GEN] Generating title for session');
|
|
305
|
-
debugLog(`[TITLE_GEN] Provider: ${provider}, Model: ${modelName}`);
|
|
306
|
-
|
|
307
287
|
const { getAuth } = await import('@ottocode/sdk');
|
|
308
288
|
const auth = await getAuth(provider, cfg.projectRoot);
|
|
309
289
|
const oauth = detectOAuth(provider, auth);
|
|
310
290
|
|
|
311
291
|
const titleModel = getFastModelForAuth(provider, auth?.type) ?? modelName;
|
|
312
|
-
debugLog(`[TITLE_GEN] Using title model: ${titleModel}`);
|
|
313
292
|
const model = await resolveModel(provider, titleModel, cfg);
|
|
314
293
|
|
|
315
|
-
debugLog(
|
|
316
|
-
`[TITLE_GEN] oauth: needsSpoof=${oauth.needsSpoof}, isOpenAIOAuth=${oauth.isOpenAIOAuth}`,
|
|
317
|
-
);
|
|
318
|
-
|
|
319
294
|
const promptText = String(content ?? '').slice(0, 2000);
|
|
320
295
|
|
|
321
296
|
const titleInstructions = `Generate a brief title (6-8 words) summarizing what the user wants to do.
|
|
@@ -330,10 +305,6 @@ Output ONLY the title, nothing else.`;
|
|
|
330
305
|
userContent: promptText,
|
|
331
306
|
});
|
|
332
307
|
|
|
333
|
-
debugLog(
|
|
334
|
-
`[TITLE_GEN] mode=${adapted.forceStream ? 'openai-oauth' : oauth.needsSpoof ? 'spoof' : 'api-key'}`,
|
|
335
|
-
);
|
|
336
|
-
|
|
337
308
|
let modelTitle = '';
|
|
338
309
|
try {
|
|
339
310
|
if (adapted.forceStream || oauth.needsSpoof) {
|
|
@@ -348,7 +319,6 @@ Output ONLY the title, nothing else.`;
|
|
|
348
319
|
}
|
|
349
320
|
modelTitle = modelTitle.trim();
|
|
350
321
|
} else {
|
|
351
|
-
debugLog('[TITLE_GEN] Using generateText...');
|
|
352
322
|
const out = await generateText({
|
|
353
323
|
model,
|
|
354
324
|
system: adapted.system,
|
|
@@ -356,24 +326,15 @@ Output ONLY the title, nothing else.`;
|
|
|
356
326
|
});
|
|
357
327
|
modelTitle = (out?.text || '').trim();
|
|
358
328
|
}
|
|
359
|
-
|
|
360
|
-
debugLog('[TITLE_GEN] Raw response from model:');
|
|
361
|
-
debugLog(`[TITLE_GEN] "${modelTitle}"`);
|
|
362
|
-
} catch (err) {
|
|
363
|
-
debugLog('[TITLE_GEN] Error generating title:');
|
|
364
|
-
debugLog(err);
|
|
365
|
-
}
|
|
329
|
+
} catch {}
|
|
366
330
|
|
|
367
331
|
if (!modelTitle) {
|
|
368
|
-
debugLog('[TITLE_GEN] No title returned, aborting');
|
|
369
332
|
return;
|
|
370
333
|
}
|
|
371
334
|
|
|
372
335
|
const sanitized = sanitizeTitle(modelTitle);
|
|
373
|
-
debugLog(`[TITLE_GEN] After sanitization: "${sanitized}"`);
|
|
374
336
|
|
|
375
337
|
if (!sanitized || sanitized === 'New Session') {
|
|
376
|
-
debugLog('[TITLE_GEN] Sanitized title is empty or default, aborting');
|
|
377
338
|
return;
|
|
378
339
|
}
|
|
379
340
|
|
|
@@ -382,17 +343,12 @@ Output ONLY the title, nothing else.`;
|
|
|
382
343
|
.set({ title: sanitized, lastActiveAt: Date.now() })
|
|
383
344
|
.where(eq(sessions.id, sessionId));
|
|
384
345
|
|
|
385
|
-
debugLog(`[TITLE_GEN] Setting final title: "${sanitized}"`);
|
|
386
|
-
|
|
387
346
|
publish({
|
|
388
347
|
type: 'session.updated',
|
|
389
348
|
sessionId,
|
|
390
349
|
payload: { id: sessionId, title: sanitized },
|
|
391
350
|
});
|
|
392
|
-
} catch
|
|
393
|
-
debugLog('[TITLE_GEN] Error in generateSessionTitle:');
|
|
394
|
-
debugLog(err);
|
|
395
|
-
}
|
|
351
|
+
} catch {}
|
|
396
352
|
}
|
|
397
353
|
|
|
398
354
|
function sanitizeTitle(raw: string): string {
|
|
@@ -424,9 +380,7 @@ async function touchSessionLastActive(args: {
|
|
|
424
380
|
.set({ lastActiveAt: Date.now() })
|
|
425
381
|
.where(eq(sessions.id, sessionId))
|
|
426
382
|
.run();
|
|
427
|
-
} catch
|
|
428
|
-
debugLog('[touchSessionLastActive] Error:', err);
|
|
429
|
-
}
|
|
383
|
+
} catch {}
|
|
430
384
|
}
|
|
431
385
|
|
|
432
386
|
export async function triggerDeferredTitleGeneration(args: {
|
|
@@ -445,9 +399,6 @@ export async function triggerDeferredTitleGeneration(args: {
|
|
|
445
399
|
.limit(1);
|
|
446
400
|
|
|
447
401
|
if (!userMessages.length || userMessages[0].role !== 'user') {
|
|
448
|
-
debugLog(
|
|
449
|
-
'[TITLE_GEN] No user message found for deferred title generation',
|
|
450
|
-
);
|
|
451
402
|
return;
|
|
452
403
|
}
|
|
453
404
|
|
|
@@ -459,9 +410,6 @@ export async function triggerDeferredTitleGeneration(args: {
|
|
|
459
410
|
.limit(1);
|
|
460
411
|
|
|
461
412
|
if (!parts.length) {
|
|
462
|
-
debugLog(
|
|
463
|
-
'[TITLE_GEN] No message parts found for deferred title generation',
|
|
464
|
-
);
|
|
465
413
|
return;
|
|
466
414
|
}
|
|
467
415
|
|
|
@@ -470,19 +418,12 @@ export async function triggerDeferredTitleGeneration(args: {
|
|
|
470
418
|
const parsed = JSON.parse(parts[0].content ?? '{}');
|
|
471
419
|
content = String(parsed.text ?? '');
|
|
472
420
|
} catch {
|
|
473
|
-
debugLog('[TITLE_GEN] Failed to parse message part content');
|
|
474
421
|
return;
|
|
475
422
|
}
|
|
476
423
|
|
|
477
424
|
if (!content) {
|
|
478
|
-
debugLog('[TITLE_GEN] Empty content for deferred title generation');
|
|
479
425
|
return;
|
|
480
426
|
}
|
|
481
|
-
|
|
482
|
-
debugLog('[TITLE_GEN] Triggering deferred title generation');
|
|
483
427
|
enqueueSessionTitle({ cfg, db, sessionId, content });
|
|
484
|
-
} catch
|
|
485
|
-
debugLog('[TITLE_GEN] Error in triggerDeferredTitleGeneration:');
|
|
486
|
-
debugLog(err);
|
|
487
|
-
}
|
|
428
|
+
} catch {}
|
|
488
429
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { debugLog } from '../debug/index.ts';
|
|
2
|
-
|
|
3
1
|
type ToolResultPart = {
|
|
4
2
|
type: string;
|
|
5
3
|
state?: string;
|
|
@@ -61,7 +59,6 @@ export class ToolHistoryTracker {
|
|
|
61
59
|
.callProviderMetadata;
|
|
62
60
|
delete (entry.part as { providerMetadata?: unknown }).providerMetadata;
|
|
63
61
|
entry.summarized = true;
|
|
64
|
-
debugLog(`[history] summarized tool output -> ${entry.summary}`);
|
|
65
62
|
}
|
|
66
63
|
}
|
|
67
64
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { providerBasePrompt } from '@ottocode/sdk';
|
|
2
|
-
import { debugLog } from '../debug/index.ts';
|
|
3
2
|
import { composeEnvironmentAndInstructions } from '../context/environment.ts';
|
|
4
3
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
5
4
|
import BASE_PROMPT from '@ottocode/sdk/prompts/base.txt' with { type: 'text' };
|
|
@@ -163,7 +162,6 @@ export async function composeSystemPrompt(options: {
|
|
|
163
162
|
|
|
164
163
|
const composed = parts.filter(Boolean).join('\n\n').trim();
|
|
165
164
|
if (composed) {
|
|
166
|
-
debugLog(`[system] pieces: ${dedupeComponents(components).join(', ')}`);
|
|
167
165
|
return {
|
|
168
166
|
prompt: composed,
|
|
169
167
|
components: dedupeComponents(components),
|
|
@@ -88,11 +88,11 @@ export function detectOAuth(
|
|
|
88
88
|
const CODEX_INSTRUCTIONS =
|
|
89
89
|
'You are a coding agent. Follow all developer messages. Use tools to complete tasks.';
|
|
90
90
|
|
|
91
|
-
export function buildCodexProviderOptions() {
|
|
91
|
+
export function buildCodexProviderOptions(instructions?: string) {
|
|
92
92
|
return {
|
|
93
93
|
openai: {
|
|
94
94
|
store: false as const,
|
|
95
|
-
instructions: CODEX_INSTRUCTIONS,
|
|
95
|
+
instructions: instructions?.trim() || CODEX_INSTRUCTIONS,
|
|
96
96
|
parallelToolCalls: false,
|
|
97
97
|
},
|
|
98
98
|
};
|
|
@@ -145,7 +145,7 @@ export function adaptSimpleCall(
|
|
|
145
145
|
content: input.userContent,
|
|
146
146
|
},
|
|
147
147
|
],
|
|
148
|
-
providerOptions: buildCodexProviderOptions(),
|
|
148
|
+
providerOptions: buildCodexProviderOptions(input.instructions),
|
|
149
149
|
forceStream: true,
|
|
150
150
|
};
|
|
151
151
|
}
|
|
@@ -229,9 +229,9 @@ export function adaptRunnerCall(
|
|
|
229
229
|
return {
|
|
230
230
|
system: '',
|
|
231
231
|
systemComponents: composed.components,
|
|
232
|
-
additionalSystemMessages: [
|
|
232
|
+
additionalSystemMessages: [],
|
|
233
233
|
maxOutputTokens: undefined,
|
|
234
|
-
providerOptions: buildCodexProviderOptions(),
|
|
234
|
+
providerOptions: buildCodexProviderOptions(composed.prompt),
|
|
235
235
|
};
|
|
236
236
|
}
|
|
237
237
|
|
|
@@ -7,7 +7,6 @@ import { toErrorPayload } from '../errors/handling.ts';
|
|
|
7
7
|
import type { RunOpts } from '../session/queue.ts';
|
|
8
8
|
import type { ToolAdapterContext } from '../../tools/adapter.ts';
|
|
9
9
|
import { pruneSession, performAutoCompaction } from '../message/compaction.ts';
|
|
10
|
-
import { debugLog } from '../debug/index.ts';
|
|
11
10
|
import { enqueueAssistantRun } from '../session/queue.ts';
|
|
12
11
|
import { clearPendingTopup } from '../topup/manager.ts';
|
|
13
12
|
|
|
@@ -77,7 +76,6 @@ export function createErrorHandler(
|
|
|
77
76
|
|
|
78
77
|
// Handle fiat payment selected - this is not an error, just a signal to pause
|
|
79
78
|
if (isFiatSelected) {
|
|
80
|
-
debugLog('[stream-handlers] Fiat payment selected, pausing request');
|
|
81
79
|
clearPendingTopup(opts.sessionId);
|
|
82
80
|
|
|
83
81
|
// Add a helpful message part telling user to complete payment
|
|
@@ -171,20 +169,9 @@ export function createErrorHandler(
|
|
|
171
169
|
errorCode === 'context_length_exceeded' ||
|
|
172
170
|
errorType === 'invalid_request_error';
|
|
173
171
|
|
|
174
|
-
debugLog(
|
|
175
|
-
`[stream-handlers] isPromptTooLong: ${isPromptTooLong}, errorCode: ${errorCode}, errorType: ${errorType}`,
|
|
176
|
-
);
|
|
177
|
-
|
|
178
172
|
if (isPromptTooLong && !opts.isCompactCommand) {
|
|
179
|
-
debugLog(
|
|
180
|
-
'[stream-handlers] Prompt too long detected, auto-compacting...',
|
|
181
|
-
);
|
|
182
|
-
|
|
183
173
|
const retries = opts.compactionRetries ?? 0;
|
|
184
174
|
if (retries >= 2) {
|
|
185
|
-
debugLog(
|
|
186
|
-
'[stream-handlers] Compaction retry limit reached, surfacing error',
|
|
187
|
-
);
|
|
188
175
|
} else {
|
|
189
176
|
await db
|
|
190
177
|
.update(messages)
|
|
@@ -243,25 +230,12 @@ export function createErrorHandler(
|
|
|
243
230
|
opts.model,
|
|
244
231
|
);
|
|
245
232
|
if (compactResult.success) {
|
|
246
|
-
debugLog(
|
|
247
|
-
`[stream-handlers] Auto-compaction succeeded: ${compactResult.summary?.slice(0, 100)}...`,
|
|
248
|
-
);
|
|
249
233
|
compactionSucceeded = true;
|
|
250
234
|
} else {
|
|
251
|
-
debugLog(
|
|
252
|
-
`[stream-handlers] Auto-compaction failed: ${compactResult.error}, falling back to prune`,
|
|
253
|
-
);
|
|
254
235
|
const pruneResult = await pruneSession(db, opts.sessionId);
|
|
255
|
-
debugLog(
|
|
256
|
-
`[stream-handlers] Fallback pruned ${pruneResult.pruned} parts, saved ~${pruneResult.saved} tokens`,
|
|
257
|
-
);
|
|
258
236
|
compactionSucceeded = pruneResult.pruned > 0;
|
|
259
237
|
}
|
|
260
|
-
} catch
|
|
261
|
-
debugLog(
|
|
262
|
-
`[stream-handlers] Auto-compact error: ${compactErr instanceof Error ? compactErr.message : String(compactErr)}`,
|
|
263
|
-
);
|
|
264
|
-
}
|
|
238
|
+
} catch {}
|
|
265
239
|
|
|
266
240
|
await db
|
|
267
241
|
.update(messages)
|
|
@@ -278,7 +252,6 @@ export function createErrorHandler(
|
|
|
278
252
|
});
|
|
279
253
|
|
|
280
254
|
if (compactionSucceeded && retryCallback) {
|
|
281
|
-
debugLog('[stream-handlers] Triggering retry after compaction...');
|
|
282
255
|
const retryMessageId = crypto.randomUUID();
|
|
283
256
|
await db.insert(messages).values({
|
|
284
257
|
id: retryMessageId,
|
|
@@ -315,9 +288,6 @@ export function createErrorHandler(
|
|
|
315
288
|
}
|
|
316
289
|
|
|
317
290
|
if (compactionSucceeded) {
|
|
318
|
-
debugLog(
|
|
319
|
-
'[stream-handlers] No retryCallback provided, cannot auto-retry',
|
|
320
|
-
);
|
|
321
291
|
return;
|
|
322
292
|
}
|
|
323
293
|
}
|
|
@@ -5,7 +5,6 @@ import { publish } from '../../events/bus.ts';
|
|
|
5
5
|
import { estimateModelCostUsd } from '@ottocode/sdk';
|
|
6
6
|
import type { RunOpts } from '../session/queue.ts';
|
|
7
7
|
import { markSessionCompacted } from '../message/compaction.ts';
|
|
8
|
-
import { debugLog } from '../debug/index.ts';
|
|
9
8
|
import type { FinishEvent } from './types.ts';
|
|
10
9
|
import {
|
|
11
10
|
normalizeUsage,
|
|
@@ -24,11 +23,7 @@ export function createFinishHandler(
|
|
|
24
23
|
return async (fin: FinishEvent) => {
|
|
25
24
|
try {
|
|
26
25
|
await completeAssistantMessageFn(fin, opts, db);
|
|
27
|
-
} catch
|
|
28
|
-
debugLog(
|
|
29
|
-
`[finish-handler] completeAssistantMessage failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
30
|
-
);
|
|
31
|
-
}
|
|
26
|
+
} catch {}
|
|
32
27
|
|
|
33
28
|
if (opts.isCompactCommand && fin.finishReason !== 'error') {
|
|
34
29
|
const assistantParts = await db
|
|
@@ -40,27 +35,15 @@ export function createFinishHandler(
|
|
|
40
35
|
);
|
|
41
36
|
|
|
42
37
|
if (!hasTextContent) {
|
|
43
|
-
debugLog(
|
|
44
|
-
'[stream-handlers] /compact finished but no summary generated, skipping compaction marking',
|
|
45
|
-
);
|
|
46
38
|
} else {
|
|
47
39
|
try {
|
|
48
|
-
debugLog(
|
|
49
|
-
`[stream-handlers] /compact complete, marking session compacted`,
|
|
50
|
-
);
|
|
51
40
|
const result = await markSessionCompacted(
|
|
52
41
|
db,
|
|
53
42
|
opts.sessionId,
|
|
54
43
|
opts.assistantMessageId,
|
|
55
44
|
);
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
59
|
-
} catch (err) {
|
|
60
|
-
debugLog(
|
|
61
|
-
`[stream-handlers] Compaction failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
62
|
-
);
|
|
63
|
-
}
|
|
45
|
+
void result;
|
|
46
|
+
} catch {}
|
|
64
47
|
}
|
|
65
48
|
}
|
|
66
49
|
|
|
@@ -6,7 +6,6 @@ import type { RunOpts } from '../session/queue.ts';
|
|
|
6
6
|
import type { ToolAdapterContext } from '../../tools/adapter.ts';
|
|
7
7
|
import type { UsageData, ProviderMetadata } from '../session/db-operations.ts';
|
|
8
8
|
import type { StepFinishEvent } from './types.ts';
|
|
9
|
-
import { debugLog } from '../debug/index.ts';
|
|
10
9
|
|
|
11
10
|
export function createStepFinishHandler(
|
|
12
11
|
opts: RunOpts,
|
|
@@ -45,11 +44,7 @@ export function createStepFinishHandler(
|
|
|
45
44
|
.set({ completedAt: finishedAt })
|
|
46
45
|
.where(eq(messageParts.id, currentPartId));
|
|
47
46
|
}
|
|
48
|
-
} catch
|
|
49
|
-
debugLog(
|
|
50
|
-
`[step-finish] Failed to update part completedAt: ${err instanceof Error ? err.message : String(err)}`,
|
|
51
|
-
);
|
|
52
|
-
}
|
|
47
|
+
} catch {}
|
|
53
48
|
|
|
54
49
|
if (step.usage) {
|
|
55
50
|
try {
|
|
@@ -59,11 +54,7 @@ export function createStepFinishHandler(
|
|
|
59
54
|
opts,
|
|
60
55
|
db,
|
|
61
56
|
);
|
|
62
|
-
} catch
|
|
63
|
-
debugLog(
|
|
64
|
-
`[step-finish] Failed to update session tokens: ${err instanceof Error ? err.message : String(err)}`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
57
|
+
} catch {}
|
|
67
58
|
|
|
68
59
|
try {
|
|
69
60
|
await updateMessageTokensIncrementalFn(
|
|
@@ -72,11 +63,7 @@ export function createStepFinishHandler(
|
|
|
72
63
|
opts,
|
|
73
64
|
db,
|
|
74
65
|
);
|
|
75
|
-
} catch
|
|
76
|
-
debugLog(
|
|
77
|
-
`[step-finish] Failed to update message tokens: ${err instanceof Error ? err.message : String(err)}`,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
66
|
+
} catch {}
|
|
80
67
|
}
|
|
81
68
|
|
|
82
69
|
try {
|
|
@@ -97,21 +84,13 @@ export function createStepFinishHandler(
|
|
|
97
84
|
payload: { stepIndex, ...step.usage },
|
|
98
85
|
});
|
|
99
86
|
}
|
|
100
|
-
} catch
|
|
101
|
-
debugLog(
|
|
102
|
-
`[step-finish] Failed to publish finish-step: ${err instanceof Error ? err.message : String(err)}`,
|
|
103
|
-
);
|
|
104
|
-
}
|
|
87
|
+
} catch {}
|
|
105
88
|
|
|
106
89
|
try {
|
|
107
90
|
const newStepIndex = incrementStepIndex();
|
|
108
91
|
sharedCtx.stepIndex = newStepIndex;
|
|
109
92
|
updateCurrentPartId(null);
|
|
110
93
|
updateAccumulated('');
|
|
111
|
-
} catch
|
|
112
|
-
debugLog(
|
|
113
|
-
`[step-finish] Failed to increment step: ${err instanceof Error ? err.message : String(err)}`,
|
|
114
|
-
);
|
|
115
|
-
}
|
|
94
|
+
} catch {}
|
|
116
95
|
};
|
|
117
96
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { publish } from '../../events/bus.ts';
|
|
2
|
-
import { debugLog } from '../debug/index.ts';
|
|
3
2
|
|
|
4
3
|
export type ToolApprovalMode = 'auto' | 'dangerous' | 'all';
|
|
5
4
|
|
|
@@ -49,12 +48,6 @@ export async function requestApproval(
|
|
|
49
48
|
args: unknown,
|
|
50
49
|
timeoutMs = 120000,
|
|
51
50
|
): Promise<boolean> {
|
|
52
|
-
debugLog('[approval] requestApproval called', {
|
|
53
|
-
sessionId,
|
|
54
|
-
messageId,
|
|
55
|
-
callId,
|
|
56
|
-
toolName,
|
|
57
|
-
});
|
|
58
51
|
return new Promise((resolve) => {
|
|
59
52
|
const approval: PendingApproval = {
|
|
60
53
|
callId,
|
|
@@ -67,10 +60,6 @@ export async function requestApproval(
|
|
|
67
60
|
};
|
|
68
61
|
|
|
69
62
|
pendingApprovals.set(callId, approval);
|
|
70
|
-
debugLog(
|
|
71
|
-
'[approval] Added to pendingApprovals, count:',
|
|
72
|
-
pendingApprovals.size,
|
|
73
|
-
);
|
|
74
63
|
|
|
75
64
|
publish({
|
|
76
65
|
type: 'tool.approval.required',
|
|
@@ -106,15 +95,8 @@ export function resolveApproval(
|
|
|
106
95
|
callId: string,
|
|
107
96
|
approved: boolean,
|
|
108
97
|
): { ok: boolean; error?: string } {
|
|
109
|
-
debugLog('[approval] resolveApproval called', {
|
|
110
|
-
callId,
|
|
111
|
-
approved,
|
|
112
|
-
pendingCount: pendingApprovals.size,
|
|
113
|
-
pendingIds: [...pendingApprovals.keys()],
|
|
114
|
-
});
|
|
115
98
|
const approval = pendingApprovals.get(callId);
|
|
116
99
|
if (!approval) {
|
|
117
|
-
debugLog('[approval] No pending approval found for callId:', callId);
|
|
118
100
|
return { ok: false, error: 'No pending approval found for this callId' };
|
|
119
101
|
}
|
|
120
102
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { catalog } from '@ottocode/sdk';
|
|
2
|
-
import { debugLog } from '../debug/index.ts';
|
|
3
2
|
import type { ProviderName } from '../provider/index.ts';
|
|
4
3
|
|
|
5
4
|
/**
|
|
@@ -16,23 +15,15 @@ export function getMaxOutputTokens(
|
|
|
16
15
|
try {
|
|
17
16
|
const providerCatalog = catalog[provider];
|
|
18
17
|
if (!providerCatalog) {
|
|
19
|
-
debugLog(`[maxOutputTokens] No catalog found for provider: ${provider}`);
|
|
20
18
|
return undefined;
|
|
21
19
|
}
|
|
22
20
|
const modelInfo = providerCatalog.models.find((m) => m.id === modelId);
|
|
23
21
|
if (!modelInfo) {
|
|
24
|
-
debugLog(
|
|
25
|
-
`[maxOutputTokens] No model info found for: ${modelId} in provider: ${provider}`,
|
|
26
|
-
);
|
|
27
22
|
return undefined;
|
|
28
23
|
}
|
|
29
24
|
const outputLimit = modelInfo.limit?.output;
|
|
30
|
-
debugLog(
|
|
31
|
-
`[maxOutputTokens] Provider: ${provider}, Model: ${modelId}, Limit: ${outputLimit}`,
|
|
32
|
-
);
|
|
33
25
|
return outputLimit;
|
|
34
|
-
} catch
|
|
35
|
-
debugLog(`[maxOutputTokens] Error looking up limit: ${err}`);
|
|
26
|
+
} catch {
|
|
36
27
|
return undefined;
|
|
37
28
|
}
|
|
38
29
|
}
|
package/src/tools/adapter.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
requestApproval,
|
|
19
19
|
} from '../runtime/tools/approval.ts';
|
|
20
20
|
import { guardToolCall } from '../runtime/tools/guards.ts';
|
|
21
|
-
import { debugLog } from '../runtime/debug/index.ts';
|
|
22
21
|
|
|
23
22
|
export type { ToolAdapterContext } from '../runtime/tools/context.ts';
|
|
24
23
|
|
|
@@ -63,17 +62,9 @@ function extractToolCallId(options: unknown): string | undefined {
|
|
|
63
62
|
const DEFAULT_TRACED_TOOL_INPUTS = new Set(['write', 'apply_patch']);
|
|
64
63
|
|
|
65
64
|
function shouldTraceToolInput(name: string): boolean {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (['1', 'true', 'yes', 'on', 'all'].includes(normalized)) {
|
|
70
|
-
return DEFAULT_TRACED_TOOL_INPUTS.has(name);
|
|
71
|
-
}
|
|
72
|
-
const tokens = raw
|
|
73
|
-
.split(/[\s,]+/)
|
|
74
|
-
.map((token) => token.trim().toLowerCase())
|
|
75
|
-
.filter(Boolean);
|
|
76
|
-
return tokens.includes('all') || tokens.includes(name.toLowerCase());
|
|
65
|
+
void DEFAULT_TRACED_TOOL_INPUTS;
|
|
66
|
+
void name;
|
|
67
|
+
return false;
|
|
77
68
|
}
|
|
78
69
|
|
|
79
70
|
function summarizeTraceValue(value: unknown, max = 160): string {
|
|
@@ -239,9 +230,7 @@ export function adaptTools(
|
|
|
239
230
|
stepIndex: ctx.stepIndex,
|
|
240
231
|
});
|
|
241
232
|
if (shouldTraceToolInput(name)) {
|
|
242
|
-
|
|
243
|
-
`[TOOL_INPUT_TRACE][adapter] onInputStart tool=${name} callId=${sdkCallId ?? queue[queue.length - 1]?.callId ?? 'unknown'} step=${ctx.stepIndex}`,
|
|
244
|
-
);
|
|
233
|
+
void (sdkCallId ?? queue[queue.length - 1]?.callId ?? 'unknown');
|
|
245
234
|
}
|
|
246
235
|
if (typeof base.onInputStart === 'function')
|
|
247
236
|
// biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
|
|
@@ -254,9 +243,8 @@ export function adaptTools(
|
|
|
254
243
|
const queue = pendingCalls.get(name);
|
|
255
244
|
const meta = queue?.length ? queue[queue.length - 1] : undefined;
|
|
256
245
|
if (shouldTraceToolInput(name)) {
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
);
|
|
246
|
+
void (sdkCallId ?? meta?.callId ?? 'unknown');
|
|
247
|
+
void summarizeTraceValue(delta ?? '');
|
|
260
248
|
}
|
|
261
249
|
// Stream tool argument deltas as events if needed
|
|
262
250
|
publish({
|
|
@@ -297,9 +285,8 @@ export function adaptTools(
|
|
|
297
285
|
const callPartId = crypto.randomUUID();
|
|
298
286
|
const startTs = meta.startTs;
|
|
299
287
|
if (shouldTraceToolInput(name)) {
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
);
|
|
288
|
+
void callId;
|
|
289
|
+
void summarizeTraceValue(args);
|
|
303
290
|
}
|
|
304
291
|
|
|
305
292
|
if (
|