@agi-cli/server 0.1.97 → 0.1.99

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": "@agi-cli/server",
3
- "version": "0.1.97",
3
+ "version": "0.1.99",
4
4
  "description": "HTTP API server for AGI CLI",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -29,8 +29,8 @@
29
29
  "typecheck": "tsc --noEmit"
30
30
  },
31
31
  "dependencies": {
32
- "@agi-cli/sdk": "0.1.97",
33
- "@agi-cli/database": "0.1.97",
32
+ "@agi-cli/sdk": "0.1.99",
33
+ "@agi-cli/database": "0.1.99",
34
34
  "drizzle-orm": "^0.44.5",
35
35
  "hono": "^4.9.9",
36
36
  "zod": "^4.1.8"
@@ -76,12 +76,15 @@ export async function updateSessionTokensIncremental(
76
76
  : priorCachedMsg;
77
77
 
78
78
  // Compute deltas for this step; clamp to 0 in case provider reports smaller values
79
+ // Cached tokens reduce the billable input, so we subtract them from the delta
79
80
  const deltaInput = Math.max(0, cumPrompt - priorPromptMsg);
80
81
  const deltaOutput = Math.max(0, cumCompletion - priorCompletionMsg);
81
82
  const deltaCached = Math.max(0, cumCached - priorCachedMsg);
82
83
  const deltaReasoning = Math.max(0, cumReasoning - priorReasoningMsg);
83
84
 
84
- const nextInputSess = priorInputSess + deltaInput;
85
+ // Session input should only count non-cached tokens
86
+ // Total cached tokens are tracked separately for reference
87
+ const nextInputSess = priorInputSess + deltaInput - deltaCached;
85
88
  const nextOutputSess = priorOutputSess + deltaOutput;
86
89
  const nextCachedSess = priorCachedSess + deltaCached;
87
90
  const nextReasoningSess = priorReasoningSess + deltaReasoning;
@@ -275,49 +275,9 @@ async function runAssistant(opts: RunOpts) {
275
275
 
276
276
  const onFinish = createFinishHandler(opts, db, completeAssistantMessage);
277
277
 
278
- // Apply optimizations: deduplication, pruning, cache control, and truncation
279
- const { addCacheControl, truncateHistory } = await import(
280
- './cache-optimizer.ts'
281
- );
282
- const { optimizeContext } = await import('./context-optimizer.ts');
283
-
284
- // 1. Optimize context (deduplicate file reads, prune old tool results)
285
- const contextOptimized = optimizeContext(messagesWithSystemInstructions, {
286
- deduplicateFiles: true,
287
- maxToolResults: 30,
288
- });
289
-
290
- debugLog(
291
- `[RUNNER] After optimizeContext: ${contextOptimized.length} messages`,
292
- );
293
-
294
- // 2. Truncate history
295
- const truncatedMessages = truncateHistory(contextOptimized, 20);
296
-
297
- debugLog(
298
- `[RUNNER] After truncateHistory: ${truncatedMessages.length} messages`,
299
- );
300
- if (truncatedMessages.length > 0 && truncatedMessages[0].role === 'system') {
301
- debugLog('[RUNNER] ✅ First message is system message');
302
- } else if (truncatedMessages.length > 0) {
303
- debugLog(
304
- `[RUNNER] ⚠️ First message is NOT system (it's ${truncatedMessages[0].role})`,
305
- );
306
- }
307
-
308
- // 3. Add cache control
309
- const { system: cachedSystem, messages: optimizedMessages } = addCacheControl(
310
- opts.provider,
311
- system,
312
- truncatedMessages,
313
- );
314
-
315
- debugLog(
316
- `[RUNNER] Final optimizedMessages: ${optimizedMessages.length} messages`,
317
- );
318
- debugLog(
319
- `[RUNNER] cachedSystem (spoof): ${typeof cachedSystem === 'string' ? cachedSystem.substring(0, 100) : JSON.stringify(cachedSystem).substring(0, 100)}`,
320
- );
278
+ // Use messages directly without truncation or optimization
279
+ const optimizedMessages = messagesWithSystemInstructions;
280
+ const cachedSystem = system;
321
281
 
322
282
  // Part tracking - will be created on first text-delta
323
283
  let currentPartId: string | null = null;
@@ -10,13 +10,6 @@ import type {
10
10
  } from '../runtime/tool-context.ts';
11
11
  import { isToolError } from '@agi-cli/sdk/tools/error';
12
12
 
13
- function isSkippedToolCallError(error: unknown): boolean {
14
- if (!isToolError(error)) return false;
15
- const details = (error as { details?: unknown }).details;
16
- if (!details || typeof details !== 'object') return false;
17
- return 'skippedTool' in (details as Record<string, unknown>);
18
- }
19
-
20
13
  export type { ToolAdapterContext } from '../runtime/tool-context.ts';
21
14
 
22
15
  type ToolExecuteSignature = Tool['execute'] extends (
@@ -227,41 +220,7 @@ export function adaptTools(
227
220
  stepIndex: ctx.stepIndex,
228
221
  },
229
222
  });
230
- // Optionally persist in the background without blocking ordering
231
- (async () => {
232
- try {
233
- const index = await ctx.nextIndex();
234
- await ctx.db.insert(messageParts).values({
235
- id: callPartId,
236
- messageId: ctx.messageId,
237
- index,
238
- stepIndex: ctx.stepIndex,
239
- type: 'tool_call',
240
- content: JSON.stringify({ name, args, callId }),
241
- agent: ctx.agent,
242
- provider: ctx.provider,
243
- model: ctx.model,
244
- startedAt: startTs,
245
- toolName: name,
246
- toolCallId: callId,
247
- });
248
- } catch {}
249
- })();
250
- if (typeof base.onInputAvailable === 'function') {
251
- // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
252
- await base.onInputAvailable(options as any);
253
- }
254
- return;
255
- }
256
-
257
- // Publish promptly so UI shows the call header before results
258
- publish({
259
- type: 'tool.call',
260
- sessionId: ctx.sessionId,
261
- payload: { name, args, callId, stepIndex: ctx.stepIndex },
262
- });
263
- // Persist best-effort in the background to avoid delaying output
264
- (async () => {
223
+ // Persist synchronously to maintain correct ordering
265
224
  try {
266
225
  const index = await ctx.nextIndex();
267
226
  await ctx.db.insert(messageParts).values({
@@ -279,7 +238,37 @@ export function adaptTools(
279
238
  toolCallId: callId,
280
239
  });
281
240
  } catch {}
282
- })();
241
+ if (typeof base.onInputAvailable === 'function') {
242
+ // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
243
+ await base.onInputAvailable(options as any);
244
+ }
245
+ return;
246
+ }
247
+
248
+ // Publish promptly so UI shows the call header before results
249
+ publish({
250
+ type: 'tool.call',
251
+ sessionId: ctx.sessionId,
252
+ payload: { name, args, callId, stepIndex: ctx.stepIndex },
253
+ });
254
+ // Persist synchronously to maintain correct ordering
255
+ try {
256
+ const index = await ctx.nextIndex();
257
+ await ctx.db.insert(messageParts).values({
258
+ id: callPartId,
259
+ messageId: ctx.messageId,
260
+ index,
261
+ stepIndex: ctx.stepIndex,
262
+ type: 'tool_call',
263
+ content: JSON.stringify({ name, args, callId }),
264
+ agent: ctx.agent,
265
+ provider: ctx.provider,
266
+ model: ctx.model,
267
+ startedAt: startTs,
268
+ toolName: name,
269
+ toolCallId: callId,
270
+ });
271
+ } catch {}
283
272
  if (typeof base.onInputAvailable === 'function') {
284
273
  // biome-ignore lint/suspicious/noExplicitAny: AI SDK types are complex
285
274
  await base.onInputAvailable(options as any);
@@ -310,23 +299,6 @@ export function adaptTools(
310
299
 
311
300
  const executeWithGuards = async (): Promise<ToolExecuteReturn> => {
312
301
  try {
313
- if (failureState.active) {
314
- const expectedTool = failureState.toolName;
315
- if (!expectedTool || expectedTool !== name) {
316
- const skipError = {
317
- ok: false,
318
- error: expectedTool
319
- ? `Cannot execute "${name}" because "${expectedTool}" failed earlier in this step. Retry "${expectedTool}" before using other tools.`
320
- : `Cannot execute "${name}" because a previous tool call in this session failed. Retry that tool before continuing with "${name}".`,
321
- details: {
322
- skippedTool: name,
323
- reason: 'previous_tool_failed',
324
- expectedTool,
325
- },
326
- };
327
- throw skipError;
328
- }
329
- }
330
302
  // Handle session-relative paths and cwd tools
331
303
  let res: ToolExecuteReturn | { cwd: string } | null | undefined;
332
304
  const cwd = getCwd(ctx.sessionId);
@@ -396,6 +368,10 @@ export function adaptTools(
396
368
 
397
369
  if (isToolError(result)) {
398
370
  stepState.failed = true;
371
+ stepState.failedToolName = name;
372
+ failureState.active = true;
373
+ failureState.toolName = name;
374
+
399
375
  await persistToolErrorResult(result, {
400
376
  callId: callIdFromQueue,
401
377
  startTs: startTsFromQueue,
@@ -403,7 +379,7 @@ export function adaptTools(
403
379
  args: meta?.args,
404
380
  });
405
381
  processedToolErrors.add(result as object);
406
- throw result;
382
+ return result as ToolExecuteReturn;
407
383
  }
408
384
 
409
385
  const resultPartId = crypto.randomUUID();
@@ -547,10 +523,6 @@ export function adaptTools(
547
523
  }
548
524
  return result as ToolExecuteReturn;
549
525
  } catch (error) {
550
- if (isSkippedToolCallError(error)) {
551
- throw error;
552
- }
553
-
554
526
  stepState.failed = true;
555
527
  stepState.failedToolName = name;
556
528
  failureState.active = true;
@@ -589,8 +561,7 @@ export function adaptTools(
589
561
  processedToolErrors.add(error as object);
590
562
  }
591
563
 
592
- // Re-throw so AI SDK can handle it
593
- throw error;
564
+ return errorResult as ToolExecuteReturn;
594
565
  }
595
566
  };
596
567