@ottocode/server 0.1.213 → 0.1.216

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.
@@ -11,7 +11,8 @@ import { discoverProjectTools } from '@ottocode/sdk';
11
11
  import type { Tool } from 'ai';
12
12
  import { adaptTools } from '../../tools/adapter.ts';
13
13
  import { buildDatabaseTools } from '../../tools/database/index.ts';
14
- import { debugLog, time, isDebugEnabled } from '../debug/index.ts';
14
+ import { debugLog, time } from '../debug/index.ts';
15
+ import { isDevtoolsEnabled } from '../debug/state.ts';
15
16
  import { buildHistoryMessages } from '../message/history-builder.ts';
16
17
  import { getMaxOutputTokens } from '../utils/token.ts';
17
18
  import { setupToolContext } from '../tools/setup.ts';
@@ -184,7 +185,7 @@ export async function setupRunner(opts: RunOpts): Promise<SetupResult> {
184
185
  sessionId: opts.sessionId,
185
186
  messageId: opts.assistantMessageId,
186
187
  });
187
- const wrappedModel = isDebugEnabled()
188
+ const wrappedModel = isDevtoolsEnabled()
188
189
  ? wrapLanguageModel({
189
190
  // biome-ignore lint/suspicious/noExplicitAny: OpenRouter provider uses v2 spec
190
191
  model: model as any,
@@ -65,6 +65,13 @@ function checkEnvTrace(): boolean {
65
65
  return false;
66
66
  }
67
67
 
68
+ function checkEnvDevtools(): boolean {
69
+ const raw = process.env.OTTO_DEVTOOLS;
70
+ if (!raw) return false;
71
+ const trimmed = raw.trim().toLowerCase();
72
+ return TRUTHY.has(trimmed);
73
+ }
74
+
68
75
  /**
69
76
  * Initialize debug state from environment
70
77
  */
@@ -96,6 +103,10 @@ export function isTraceEnabled(): boolean {
96
103
  return state.enabled && state.traceEnabled;
97
104
  }
98
105
 
106
+ export function isDevtoolsEnabled(): boolean {
107
+ return checkEnvDevtools();
108
+ }
109
+
99
110
  /**
100
111
  * Enable or disable debug mode at runtime
101
112
  * Overrides environment variable settings
@@ -24,26 +24,30 @@ export async function buildHistoryMessages(
24
24
  const toolHistory = new ToolHistoryTracker();
25
25
 
26
26
  for (const m of rows) {
27
+ const parts = await db
28
+ .select()
29
+ .from(messageParts)
30
+ .where(eq(messageParts.messageId, m.id))
31
+ .orderBy(asc(messageParts.index));
32
+
27
33
  if (
28
34
  m.role === 'assistant' &&
29
35
  m.status !== 'complete' &&
30
36
  m.status !== 'completed' &&
31
- m.status !== 'error' &&
32
- m.id !== currentMessageId
37
+ m.status !== 'error'
33
38
  ) {
39
+ if (parts.length === 0) {
40
+ debugLog(
41
+ `[buildHistoryMessages] Skipping empty assistant message ${m.id} with status ${m.status}`,
42
+ );
43
+ continue;
44
+ }
45
+
34
46
  debugLog(
35
- `[buildHistoryMessages] Skipping assistant message ${m.id} with status ${m.status}`,
47
+ `[buildHistoryMessages] Including non-complete assistant message ${m.id} (status: ${m.status}) with ${parts.length} parts to preserve context`,
36
48
  );
37
- logPendingToolParts(db, m.id);
38
- continue;
39
49
  }
40
50
 
41
- const parts = await db
42
- .select()
43
- .from(messageParts)
44
- .where(eq(messageParts.messageId, m.id))
45
- .orderBy(asc(messageParts.index));
46
-
47
51
  if (m.role === 'user') {
48
52
  const uparts: UIMessage['parts'] = [];
49
53
  for (const p of parts) {
@@ -123,7 +127,6 @@ export async function buildHistoryMessages(
123
127
  if (t) assistantParts.push({ type: 'text', text: t });
124
128
  } catch {}
125
129
  } else if (p.type === 'tool_call') {
126
- // Skip compacted tool calls entirely
127
130
  if (p.compactedAt) continue;
128
131
 
129
132
  try {
@@ -141,7 +144,6 @@ export async function buildHistoryMessages(
141
144
  }
142
145
  } catch {}
143
146
  } else if (p.type === 'tool_result') {
144
- // Skip compacted tool results entirely
145
147
  if (p.compactedAt) continue;
146
148
 
147
149
  try {
@@ -159,7 +161,6 @@ export async function buildHistoryMessages(
159
161
  }
160
162
  } catch {}
161
163
  }
162
- // Skip error parts in history
163
164
  }
164
165
 
165
166
  const toolResultsById = new Map(
@@ -167,14 +168,12 @@ export async function buildHistoryMessages(
167
168
  );
168
169
 
169
170
  for (const call of toolCalls) {
170
- // Skip finish tool from history - it's internal loop control
171
171
  if (call.name === 'finish') continue;
172
172
 
173
173
  const toolType = `tool-${call.name}` as `tool-${string}`;
174
174
  let result = toolResultsById.get(call.callId);
175
175
 
176
176
  if (!result) {
177
- // Synthesize a result for incomplete tool calls to preserve history
178
177
  debugLog(
179
178
  `[buildHistoryMessages] Synthesizing error result for incomplete tool call ${call.name}#${call.callId}`,
180
179
  );
@@ -5,7 +5,7 @@ import {
5
5
  loadConfig,
6
6
  } from '@ottocode/sdk';
7
7
  import { devToolsMiddleware } from '@ai-sdk/devtools';
8
- import { isDebugEnabled } from '../debug/index.ts';
8
+ import { isDevtoolsEnabled } from '../debug/state.ts';
9
9
  import { publish } from '../../events/bus.ts';
10
10
  import {
11
11
  waitForTopupMethodSelection,
@@ -123,7 +123,7 @@ export async function resolveSetuModel(
123
123
  baseURL,
124
124
  rpcURL,
125
125
  callbacks,
126
- middleware: isDebugEnabled() ? devToolsMiddleware() : undefined,
126
+ middleware: isDevtoolsEnabled() ? devToolsMiddleware() : undefined,
127
127
  payment: {
128
128
  topupApprovalMode,
129
129
  autoPayThresholdUsd,
@@ -140,7 +140,7 @@ const SENSITIVE_WRITE_PATHS: Array<{ pattern: RegExp; reason: string }> = [
140
140
  ];
141
141
 
142
142
  function guardWritePath(
143
- toolName: string,
143
+ _toolName: string,
144
144
  args: Record<string, unknown>,
145
145
  ): GuardAction {
146
146
  const path =