@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.
@@ -1,18 +1,28 @@
1
1
  import type { getDb } from '@ottocode/database';
2
2
  import { messages, messageParts } from '@ottocode/database/schema';
3
3
  import { eq, asc, and, lt } from 'drizzle-orm';
4
- import { debugLog } from '../debug/index.ts';
5
4
  import { estimateTokens, PRUNE_PROTECT } from './compaction-limits.ts';
6
5
 
7
6
  const PROTECTED_TOOLS = ['skill'];
8
7
 
8
+ type PartInfo = {
9
+ id: string;
10
+ tokens: number;
11
+ toolCallId: string | null;
12
+ type: 'tool_call' | 'tool_result';
13
+ index: number;
14
+ };
15
+
16
+ type CompactUnit = {
17
+ partIds: string[];
18
+ tokens: number;
19
+ };
20
+
9
21
  export async function markSessionCompacted(
10
22
  db: Awaited<ReturnType<typeof getDb>>,
11
23
  sessionId: string,
12
24
  compactMessageId: string,
13
25
  ): Promise<{ compacted: number; saved: number }> {
14
- debugLog(`[compaction] Marking session ${sessionId} as compacted`);
15
-
16
26
  const compactMsg = await db
17
27
  .select()
18
28
  .from(messages)
@@ -20,7 +30,6 @@ export async function markSessionCompacted(
20
30
  .limit(1);
21
31
 
22
32
  if (!compactMsg.length) {
23
- debugLog('[compaction] Compact message not found');
24
33
  return { compacted: 0, saved: 0 };
25
34
  }
26
35
 
@@ -37,8 +46,7 @@ export async function markSessionCompacted(
37
46
  )
38
47
  .orderBy(asc(messages.createdAt));
39
48
 
40
- type PartInfo = { id: string; tokens: number };
41
- const allToolParts: PartInfo[] = [];
49
+ const allCompactUnits: CompactUnit[] = [];
42
50
  let totalToolTokens = 0;
43
51
 
44
52
  for (const msg of oldMessages) {
@@ -48,6 +56,8 @@ export async function markSessionCompacted(
48
56
  .where(eq(messageParts.messageId, msg.id))
49
57
  .orderBy(asc(messageParts.index));
50
58
 
59
+ const eligibleParts: PartInfo[] = [];
60
+
51
61
  for (const part of parts) {
52
62
  if (part.type !== 'tool_call' && part.type !== 'tool_result') continue;
53
63
  if (part.toolName && PROTECTED_TOOLS.includes(part.toolName)) continue;
@@ -69,43 +79,81 @@ export async function markSessionCompacted(
69
79
 
70
80
  const tokens = estimateTokens(contentStr);
71
81
  totalToolTokens += tokens;
72
- allToolParts.push({ id: part.id, tokens });
82
+ eligibleParts.push({
83
+ id: part.id,
84
+ tokens,
85
+ toolCallId: part.toolCallId,
86
+ type: part.type,
87
+ index: part.index,
88
+ });
89
+ }
90
+
91
+ const pairedCallIds = new Set<string>();
92
+ const callsById = new Map<string, PartInfo[]>();
93
+ const resultsById = new Map<string, PartInfo[]>();
94
+
95
+ for (const part of eligibleParts) {
96
+ if (!part.toolCallId) continue;
97
+ const bucket = part.type === 'tool_call' ? callsById : resultsById;
98
+ const items = bucket.get(part.toolCallId) ?? [];
99
+ items.push(part);
100
+ bucket.set(part.toolCallId, items);
101
+ }
102
+
103
+ for (const [toolCallId, callParts] of callsById) {
104
+ const resultParts = resultsById.get(toolCallId);
105
+ if (!resultParts?.length) continue;
106
+
107
+ const pairParts = [...callParts, ...resultParts].sort(
108
+ (a, b) => a.index - b.index,
109
+ );
110
+ pairedCallIds.add(toolCallId);
111
+ allCompactUnits.push({
112
+ partIds: pairParts.map((part) => part.id),
113
+ tokens: pairParts.reduce((sum, part) => sum + part.tokens, 0),
114
+ });
115
+ }
116
+
117
+ for (const part of eligibleParts) {
118
+ if (part.toolCallId && pairedCallIds.has(part.toolCallId)) continue;
119
+ allCompactUnits.push({
120
+ partIds: [part.id],
121
+ tokens: part.tokens,
122
+ });
73
123
  }
74
124
  }
75
125
 
76
126
  const tokensToFree = Math.max(0, totalToolTokens - PRUNE_PROTECT);
77
127
 
78
- const toCompact: PartInfo[] = [];
128
+ const toCompact: CompactUnit[] = [];
79
129
  let freedTokens = 0;
80
130
 
81
- for (const part of allToolParts) {
131
+ for (const unit of allCompactUnits) {
82
132
  if (freedTokens >= tokensToFree) break;
83
- freedTokens += part.tokens;
84
- toCompact.push(part);
133
+ freedTokens += unit.tokens;
134
+ toCompact.push(unit);
85
135
  }
86
136
 
87
- debugLog(
88
- `[compaction] Found ${toCompact.length} parts to compact (oldest first), saving ~${freedTokens} tokens`,
89
- );
90
-
91
137
  if (toCompact.length > 0) {
92
138
  const compactedAt = Date.now();
93
139
 
94
- for (const part of toCompact) {
95
- try {
96
- await db
97
- .update(messageParts)
98
- .set({ compactedAt })
99
- .where(eq(messageParts.id, part.id));
100
- } catch (err) {
101
- debugLog(
102
- `[compaction] Failed to mark part ${part.id}: ${err instanceof Error ? err.message : String(err)}`,
103
- );
140
+ for (const unit of toCompact) {
141
+ for (const partId of unit.partIds) {
142
+ try {
143
+ await db
144
+ .update(messageParts)
145
+ .set({ compactedAt })
146
+ .where(eq(messageParts.id, partId));
147
+ } catch {}
104
148
  }
105
149
  }
106
150
 
107
- debugLog(`[compaction] Marked ${toCompact.length} parts as compacted`);
151
+ const compactedParts = toCompact.reduce(
152
+ (sum, unit) => sum + unit.partIds.length,
153
+ 0,
154
+ );
155
+ return { compacted: compactedParts, saved: freedTokens };
108
156
  }
109
157
 
110
- return { compacted: toCompact.length, saved: freedTokens };
158
+ return { compacted: 0, saved: freedTokens };
111
159
  }
@@ -1,7 +1,6 @@
1
1
  import type { getDb } from '@ottocode/database';
2
2
  import { messages, messageParts } from '@ottocode/database/schema';
3
3
  import { eq, desc } from 'drizzle-orm';
4
- import { debugLog } from '../debug/index.ts';
5
4
  import { estimateTokens, PRUNE_PROTECT } from './compaction-limits.ts';
6
5
 
7
6
  const PROTECTED_TOOLS = ['skill'];
@@ -10,8 +9,6 @@ export async function pruneSession(
10
9
  db: Awaited<ReturnType<typeof getDb>>,
11
10
  sessionId: string,
12
11
  ): Promise<{ pruned: number; saved: number }> {
13
- debugLog(`[compaction] Auto-pruning session ${sessionId}`);
14
-
15
12
  const allMessages = await db
16
13
  .select()
17
14
  .from(messages)
@@ -8,7 +8,6 @@ import {
8
8
  import type { getDb } from '@ottocode/database';
9
9
  import { messages, messageParts } from '@ottocode/database/schema';
10
10
  import { eq, asc } from 'drizzle-orm';
11
- import { debugLog } from '../debug/index.ts';
12
11
  import { ToolHistoryTracker } from './tool-history-tracker.ts';
13
12
 
14
13
  /**
@@ -43,15 +42,8 @@ export async function buildHistoryMessages(
43
42
  m.status !== 'error'
44
43
  ) {
45
44
  if (parts.length === 0) {
46
- debugLog(
47
- `[buildHistoryMessages] Skipping empty assistant message ${m.id} with status ${m.status}`,
48
- );
49
45
  continue;
50
46
  }
51
-
52
- debugLog(
53
- `[buildHistoryMessages] Including non-complete assistant message ${m.id} (status: ${m.status}) with ${parts.length} parts to preserve context`,
54
- );
55
47
  }
56
48
 
57
49
  if (m.role === 'user') {
@@ -179,9 +171,6 @@ export async function buildHistoryMessages(
179
171
  let result = toolResultsById.get(obj.callId);
180
172
 
181
173
  if (!result) {
182
- debugLog(
183
- `[buildHistoryMessages] Synthesizing error result for incomplete tool call ${obj.name}#${obj.callId}`,
184
- );
185
174
  result = {
186
175
  name: obj.name,
187
176
  callId: obj.callId,
@@ -265,16 +254,6 @@ async function _logPendingToolParts(
265
254
  }
266
255
  } catch {}
267
256
  }
268
- if (pendingCalls.length) {
269
- debugLog(
270
- `[buildHistoryMessages] Pending tool calls for assistant message ${messageId}: ${pendingCalls.join(', ')}`,
271
- );
272
- }
273
- } catch (err) {
274
- debugLog(
275
- `[buildHistoryMessages] Failed to inspect pending tool calls for ${messageId}: ${
276
- err instanceof Error ? err.message : String(err)
277
- }`,
278
- );
279
- }
257
+ void pendingCalls;
258
+ } catch {}
280
259
  }
@@ -9,10 +9,10 @@ import { runSessionLoop } from '../agent/runner.ts';
9
9
  import { resolveModel } from '../provider/index.ts';
10
10
  import {
11
11
  getFastModelForAuth,
12
+ logger,
12
13
  type ProviderId,
13
14
  type ReasoningLevel,
14
15
  } from '@ottocode/sdk';
15
- import { debugLog } from '../debug/index.ts';
16
16
  import { isCompactCommand, buildCompactionContext } from './compaction.ts';
17
17
  import { detectOAuth, adaptSimpleCall } from '../provider/oauth-adapter.ts';
18
18
 
@@ -59,13 +59,17 @@ export async function dispatchAssistantMessage(
59
59
  files,
60
60
  } = options;
61
61
 
62
- debugLog(
63
- `[MESSAGE_SERVICE] dispatchAssistantMessage called with userContext: ${userContext ? `${userContext.substring(0, 50)}...` : 'NONE'}`,
64
- );
65
-
66
62
  const sessionId = session.id;
67
63
  const now = Date.now();
68
64
  const userMessageId = crypto.randomUUID();
65
+ logger.debug('[agent] dispatching assistant message', {
66
+ sessionId,
67
+ agent,
68
+ provider,
69
+ model,
70
+ oneShot: Boolean(oneShot),
71
+ hasUserContext: Boolean(userContext),
72
+ });
69
73
 
70
74
  await db.insert(messages).values({
71
75
  id: userMessageId,
@@ -163,15 +167,10 @@ export async function dispatchAssistantMessage(
163
167
  },
164
168
  });
165
169
 
166
- debugLog(
167
- `[MESSAGE_SERVICE] Enqueuing assistant run with userContext: ${userContext ? `${userContext.substring(0, 50)}...` : 'NONE'}`,
168
- );
169
-
170
170
  const isCompact = isCompactCommand(content);
171
171
  let compactionContext: string | undefined;
172
172
 
173
173
  if (isCompact) {
174
- debugLog('[MESSAGE_SERVICE] Detected /compact command, building context');
175
174
  const { getModelLimits } = await import('./compaction.ts');
176
175
  const limits = getModelLimits(provider, model);
177
176
  const contextTokenLimit = limits
@@ -182,9 +181,6 @@ export async function dispatchAssistantMessage(
182
181
  sessionId,
183
182
  contextTokenLimit,
184
183
  );
185
- debugLog(
186
- `[message-service] /compact context length: ${compactionContext.length}, limit: ${contextTokenLimit} tokens`,
187
- );
188
184
  }
189
185
 
190
186
  const toolApprovalMode = cfg.defaults.toolApproval ?? 'dangerous';
@@ -207,6 +203,14 @@ export async function dispatchAssistantMessage(
207
203
  },
208
204
  runSessionLoop,
209
205
  );
206
+ logger.debug('[agent] assistant run enqueued', {
207
+ sessionId,
208
+ assistantMessageId,
209
+ agent,
210
+ provider,
211
+ model,
212
+ isCompactCommand: isCompact,
213
+ });
210
214
 
211
215
  void touchSessionLastActive({ db, sessionId });
212
216
 
@@ -249,9 +253,7 @@ function scheduleSessionTitle(args: {
249
253
  titlePending.delete(sessionId);
250
254
  try {
251
255
  await generateSessionTitle({ cfg, db, sessionId, content });
252
- } catch (err) {
253
- debugLog('[TITLE_GEN] Title generation error:');
254
- debugLog(err);
256
+ } catch {
255
257
  } finally {
256
258
  titleInFlight.delete(sessionId);
257
259
  titleActiveCount--;
@@ -288,34 +290,24 @@ async function generateSessionTitle(args: {
288
290
  .where(eq(sessions.id, sessionId));
289
291
 
290
292
  if (!existingSession.length) {
291
- debugLog('[TITLE_GEN] Session not found, aborting');
292
293
  return;
293
294
  }
294
295
 
295
296
  const sess = existingSession[0];
296
297
  if (sess.title && sess.title !== 'New Session') {
297
- debugLog('[TITLE_GEN] Session already has a title, skipping');
298
298
  return;
299
299
  }
300
300
 
301
301
  const provider = (sess.provider ?? cfg.defaults.provider) as ProviderId;
302
302
  const modelName = sess.model ?? cfg.defaults.model;
303
303
 
304
- debugLog('[TITLE_GEN] Generating title for session');
305
- debugLog(`[TITLE_GEN] Provider: ${provider}, Model: ${modelName}`);
306
-
307
304
  const { getAuth } = await import('@ottocode/sdk');
308
305
  const auth = await getAuth(provider, cfg.projectRoot);
309
306
  const oauth = detectOAuth(provider, auth);
310
307
 
311
308
  const titleModel = getFastModelForAuth(provider, auth?.type) ?? modelName;
312
- debugLog(`[TITLE_GEN] Using title model: ${titleModel}`);
313
309
  const model = await resolveModel(provider, titleModel, cfg);
314
310
 
315
- debugLog(
316
- `[TITLE_GEN] oauth: needsSpoof=${oauth.needsSpoof}, isOpenAIOAuth=${oauth.isOpenAIOAuth}`,
317
- );
318
-
319
311
  const promptText = String(content ?? '').slice(0, 2000);
320
312
 
321
313
  const titleInstructions = `Generate a brief title (6-8 words) summarizing what the user wants to do.
@@ -330,10 +322,6 @@ Output ONLY the title, nothing else.`;
330
322
  userContent: promptText,
331
323
  });
332
324
 
333
- debugLog(
334
- `[TITLE_GEN] mode=${adapted.forceStream ? 'openai-oauth' : oauth.needsSpoof ? 'spoof' : 'api-key'}`,
335
- );
336
-
337
325
  let modelTitle = '';
338
326
  try {
339
327
  if (adapted.forceStream || oauth.needsSpoof) {
@@ -348,7 +336,6 @@ Output ONLY the title, nothing else.`;
348
336
  }
349
337
  modelTitle = modelTitle.trim();
350
338
  } else {
351
- debugLog('[TITLE_GEN] Using generateText...');
352
339
  const out = await generateText({
353
340
  model,
354
341
  system: adapted.system,
@@ -356,24 +343,15 @@ Output ONLY the title, nothing else.`;
356
343
  });
357
344
  modelTitle = (out?.text || '').trim();
358
345
  }
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
- }
346
+ } catch {}
366
347
 
367
348
  if (!modelTitle) {
368
- debugLog('[TITLE_GEN] No title returned, aborting');
369
349
  return;
370
350
  }
371
351
 
372
352
  const sanitized = sanitizeTitle(modelTitle);
373
- debugLog(`[TITLE_GEN] After sanitization: "${sanitized}"`);
374
353
 
375
354
  if (!sanitized || sanitized === 'New Session') {
376
- debugLog('[TITLE_GEN] Sanitized title is empty or default, aborting');
377
355
  return;
378
356
  }
379
357
 
@@ -382,17 +360,12 @@ Output ONLY the title, nothing else.`;
382
360
  .set({ title: sanitized, lastActiveAt: Date.now() })
383
361
  .where(eq(sessions.id, sessionId));
384
362
 
385
- debugLog(`[TITLE_GEN] Setting final title: "${sanitized}"`);
386
-
387
363
  publish({
388
364
  type: 'session.updated',
389
365
  sessionId,
390
366
  payload: { id: sessionId, title: sanitized },
391
367
  });
392
- } catch (err) {
393
- debugLog('[TITLE_GEN] Error in generateSessionTitle:');
394
- debugLog(err);
395
- }
368
+ } catch {}
396
369
  }
397
370
 
398
371
  function sanitizeTitle(raw: string): string {
@@ -424,9 +397,7 @@ async function touchSessionLastActive(args: {
424
397
  .set({ lastActiveAt: Date.now() })
425
398
  .where(eq(sessions.id, sessionId))
426
399
  .run();
427
- } catch (err) {
428
- debugLog('[touchSessionLastActive] Error:', err);
429
- }
400
+ } catch {}
430
401
  }
431
402
 
432
403
  export async function triggerDeferredTitleGeneration(args: {
@@ -445,9 +416,6 @@ export async function triggerDeferredTitleGeneration(args: {
445
416
  .limit(1);
446
417
 
447
418
  if (!userMessages.length || userMessages[0].role !== 'user') {
448
- debugLog(
449
- '[TITLE_GEN] No user message found for deferred title generation',
450
- );
451
419
  return;
452
420
  }
453
421
 
@@ -459,9 +427,6 @@ export async function triggerDeferredTitleGeneration(args: {
459
427
  .limit(1);
460
428
 
461
429
  if (!parts.length) {
462
- debugLog(
463
- '[TITLE_GEN] No message parts found for deferred title generation',
464
- );
465
430
  return;
466
431
  }
467
432
 
@@ -470,19 +435,12 @@ export async function triggerDeferredTitleGeneration(args: {
470
435
  const parsed = JSON.parse(parts[0].content ?? '{}');
471
436
  content = String(parsed.text ?? '');
472
437
  } catch {
473
- debugLog('[TITLE_GEN] Failed to parse message part content');
474
438
  return;
475
439
  }
476
440
 
477
441
  if (!content) {
478
- debugLog('[TITLE_GEN] Empty content for deferred title generation');
479
442
  return;
480
443
  }
481
-
482
- debugLog('[TITLE_GEN] Triggering deferred title generation');
483
444
  enqueueSessionTitle({ cfg, db, sessionId, content });
484
- } catch (err) {
485
- debugLog('[TITLE_GEN] Error in triggerDeferredTitleGeneration:');
486
- debugLog(err);
487
- }
445
+ } catch {}
488
446
  }
@@ -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: [{ role: 'system', content: composed.prompt }],
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 (compactErr) {
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 (err) {
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
- debugLog(
57
- `[stream-handlers] Compacted ${result.compacted} parts, saved ~${result.saved} tokens`,
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