@link-assistant/agent 0.16.14 → 0.16.16
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 +1 -1
- package/src/provider/provider.ts +22 -15
- package/src/session/index.ts +42 -2
package/package.json
CHANGED
package/src/provider/provider.ts
CHANGED
|
@@ -1272,22 +1272,26 @@ export namespace Provider {
|
|
|
1272
1272
|
}
|
|
1273
1273
|
}
|
|
1274
1274
|
|
|
1275
|
-
|
|
1276
|
-
|
|
1275
|
+
// Use direct (non-lazy) logging for HTTP request/response to ensure output
|
|
1276
|
+
// is not lost when piped through external process wrappers (e.g., solve.mjs).
|
|
1277
|
+
// The verbose check is already done above, so lazy evaluation is not needed here.
|
|
1278
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
1279
|
+
log.info('HTTP request', {
|
|
1277
1280
|
providerID: provider.id,
|
|
1278
1281
|
method,
|
|
1279
1282
|
url,
|
|
1280
1283
|
headers: sanitizedHeaders,
|
|
1281
1284
|
bodyPreview,
|
|
1282
|
-
})
|
|
1285
|
+
});
|
|
1283
1286
|
|
|
1284
1287
|
const startMs = Date.now();
|
|
1285
1288
|
try {
|
|
1286
1289
|
const response = await innerFetch(input, init);
|
|
1287
1290
|
const durationMs = Date.now() - startMs;
|
|
1288
1291
|
|
|
1289
|
-
|
|
1290
|
-
|
|
1292
|
+
// Use direct (non-lazy) logging to ensure HTTP response details are captured
|
|
1293
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
1294
|
+
log.info('HTTP response', {
|
|
1291
1295
|
providerID: provider.id,
|
|
1292
1296
|
method,
|
|
1293
1297
|
url,
|
|
@@ -1295,7 +1299,7 @@ export namespace Provider {
|
|
|
1295
1299
|
statusText: response.statusText,
|
|
1296
1300
|
durationMs,
|
|
1297
1301
|
responseHeaders: Object.fromEntries(response.headers.entries()),
|
|
1298
|
-
})
|
|
1302
|
+
});
|
|
1299
1303
|
|
|
1300
1304
|
// Log response body for debugging provider failures
|
|
1301
1305
|
// For streaming responses (SSE/event-stream), tee() the stream so the AI SDK
|
|
@@ -1335,14 +1339,15 @@ export namespace Provider {
|
|
|
1335
1339
|
}
|
|
1336
1340
|
}
|
|
1337
1341
|
}
|
|
1338
|
-
|
|
1339
|
-
|
|
1342
|
+
// Use direct (non-lazy) logging for stream body
|
|
1343
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
1344
|
+
log.info('HTTP response body (stream)', {
|
|
1340
1345
|
providerID: provider.id,
|
|
1341
1346
|
url,
|
|
1342
1347
|
bodyPreview: truncated
|
|
1343
1348
|
? bodyPreview + `... [truncated]`
|
|
1344
1349
|
: bodyPreview,
|
|
1345
|
-
})
|
|
1350
|
+
});
|
|
1346
1351
|
} catch {
|
|
1347
1352
|
// Ignore logging errors — do not affect the SDK stream
|
|
1348
1353
|
}
|
|
@@ -1362,12 +1367,13 @@ export namespace Provider {
|
|
|
1362
1367
|
? bodyText.slice(0, responseBodyMaxChars) +
|
|
1363
1368
|
`... [truncated, total ${bodyText.length} chars]`
|
|
1364
1369
|
: bodyText;
|
|
1365
|
-
|
|
1366
|
-
|
|
1370
|
+
// Use direct (non-lazy) logging for non-streaming body
|
|
1371
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
1372
|
+
log.info('HTTP response body', {
|
|
1367
1373
|
providerID: provider.id,
|
|
1368
1374
|
url,
|
|
1369
1375
|
bodyPreview,
|
|
1370
|
-
})
|
|
1376
|
+
});
|
|
1371
1377
|
return new Response(bodyText, {
|
|
1372
1378
|
status: response.status,
|
|
1373
1379
|
statusText: response.statusText,
|
|
@@ -1379,8 +1385,9 @@ export namespace Provider {
|
|
|
1379
1385
|
return response;
|
|
1380
1386
|
} catch (error) {
|
|
1381
1387
|
const durationMs = Date.now() - startMs;
|
|
1382
|
-
|
|
1383
|
-
|
|
1388
|
+
// Use direct (non-lazy) logging for error path
|
|
1389
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
1390
|
+
log.error('HTTP request failed', {
|
|
1384
1391
|
providerID: provider.id,
|
|
1385
1392
|
method,
|
|
1386
1393
|
url,
|
|
@@ -1389,7 +1396,7 @@ export namespace Provider {
|
|
|
1389
1396
|
error instanceof Error
|
|
1390
1397
|
? { name: error.name, message: error.message }
|
|
1391
1398
|
: String(error),
|
|
1392
|
-
})
|
|
1399
|
+
});
|
|
1393
1400
|
throw error;
|
|
1394
1401
|
}
|
|
1395
1402
|
};
|
package/src/session/index.ts
CHANGED
|
@@ -630,9 +630,14 @@ export namespace Session {
|
|
|
630
630
|
}
|
|
631
631
|
| undefined;
|
|
632
632
|
|
|
633
|
+
// Check if standard usage has valid data (inputTokens or outputTokens defined)
|
|
634
|
+
// Also check for zero-valued tokens (some providers set them to 0 instead of undefined)
|
|
633
635
|
const standardUsageIsEmpty =
|
|
634
|
-
input.usage.inputTokens === undefined &&
|
|
635
|
-
|
|
636
|
+
(input.usage.inputTokens === undefined &&
|
|
637
|
+
input.usage.outputTokens === undefined) ||
|
|
638
|
+
(input.usage.inputTokens === 0 &&
|
|
639
|
+
input.usage.outputTokens === 0 &&
|
|
640
|
+
!input.usage.totalTokens);
|
|
636
641
|
|
|
637
642
|
// If standard usage is empty but openrouter metadata has usage, use it as source
|
|
638
643
|
let effectiveUsage = input.usage;
|
|
@@ -658,6 +663,41 @@ export namespace Session {
|
|
|
658
663
|
};
|
|
659
664
|
}
|
|
660
665
|
|
|
666
|
+
// If still empty, try providerMetadata.anthropic.usage as fallback
|
|
667
|
+
// Some providers (e.g., opencode using @ai-sdk/anthropic) return usage in
|
|
668
|
+
// Anthropic-specific metadata with snake_case keys (input_tokens, output_tokens)
|
|
669
|
+
// while the standard AI SDK usage object remains empty.
|
|
670
|
+
// See: https://github.com/link-assistant/agent/issues/211
|
|
671
|
+
if (standardUsageIsEmpty && !openrouterUsage) {
|
|
672
|
+
const anthropicUsage = input.metadata?.['anthropic']?.['usage'] as
|
|
673
|
+
| {
|
|
674
|
+
input_tokens?: number;
|
|
675
|
+
output_tokens?: number;
|
|
676
|
+
cache_creation_input_tokens?: number;
|
|
677
|
+
cache_read_input_tokens?: number;
|
|
678
|
+
}
|
|
679
|
+
| undefined;
|
|
680
|
+
|
|
681
|
+
if (
|
|
682
|
+
anthropicUsage &&
|
|
683
|
+
(anthropicUsage.input_tokens || anthropicUsage.output_tokens)
|
|
684
|
+
) {
|
|
685
|
+
if (Flag.OPENCODE_VERBOSE) {
|
|
686
|
+
log.debug(() => ({
|
|
687
|
+
message:
|
|
688
|
+
'Standard usage empty, falling back to anthropic provider metadata',
|
|
689
|
+
anthropicUsage: JSON.stringify(anthropicUsage),
|
|
690
|
+
}));
|
|
691
|
+
}
|
|
692
|
+
effectiveUsage = {
|
|
693
|
+
...input.usage,
|
|
694
|
+
inputTokens: anthropicUsage.input_tokens ?? 0,
|
|
695
|
+
outputTokens: anthropicUsage.output_tokens ?? 0,
|
|
696
|
+
cachedInputTokens: anthropicUsage.cache_read_input_tokens ?? 0,
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
|
|
661
701
|
// Extract top-level cachedInputTokens
|
|
662
702
|
const topLevelCachedInputTokens = safeNum(
|
|
663
703
|
toNumber(effectiveUsage.cachedInputTokens, 'cachedInputTokens')
|