@link-assistant/agent 0.8.17 → 0.8.19
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 +2 -2
- package/src/index.js +7 -2
- package/src/provider/provider.ts +18 -1
- package/src/session/index.ts +21 -0
- package/src/session/processor.ts +37 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@link-assistant/agent",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.19",
|
|
4
4
|
"description": "A minimal, public domain AI CLI agent compatible with OpenCode's JSON interface. Bun-only runtime.",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@standard-community/standard-json": "^0.3.5",
|
|
72
72
|
"@standard-community/standard-openapi": "^0.2.9",
|
|
73
73
|
"@zip.js/zip.js": "^2.8.10",
|
|
74
|
-
"ai": "6.0.
|
|
74
|
+
"ai": "^6.0.1",
|
|
75
75
|
"chokidar": "^4.0.3",
|
|
76
76
|
"clipboardy": "^5.0.0",
|
|
77
77
|
"command-stream": "^0.7.1",
|
package/src/index.js
CHANGED
|
@@ -68,11 +68,16 @@ process.on('uncaughtException', (error) => {
|
|
|
68
68
|
|
|
69
69
|
process.on('unhandledRejection', (reason, _promise) => {
|
|
70
70
|
hasError = true;
|
|
71
|
-
|
|
71
|
+
const errorOutput = {
|
|
72
72
|
errorType: 'UnhandledRejection',
|
|
73
73
|
message: reason?.message || String(reason),
|
|
74
74
|
stack: reason?.stack,
|
|
75
|
-
}
|
|
75
|
+
};
|
|
76
|
+
// If the error has a data property with a suggestion (e.g., ProviderModelNotFoundError), add it as a hint
|
|
77
|
+
if (reason?.data?.suggestion) {
|
|
78
|
+
errorOutput.hint = reason.data.suggestion;
|
|
79
|
+
}
|
|
80
|
+
outputError(errorOutput);
|
|
76
81
|
process.exit(1);
|
|
77
82
|
});
|
|
78
83
|
|
package/src/provider/provider.ts
CHANGED
|
@@ -909,7 +909,23 @@ export namespace Provider {
|
|
|
909
909
|
log.info(() => ({ message: 'getModel', providerID, modelID }));
|
|
910
910
|
|
|
911
911
|
const provider = s.providers[providerID];
|
|
912
|
-
if (!provider)
|
|
912
|
+
if (!provider) {
|
|
913
|
+
// Check if this model ID might exist in another provider (e.g., OpenRouter)
|
|
914
|
+
// This helps users who use formats like "z-ai/glm-4.7" instead of "openrouter/z-ai/glm-4.7"
|
|
915
|
+
const fullModelKey = `${providerID}/${modelID}`;
|
|
916
|
+
let suggestion: string | undefined;
|
|
917
|
+
|
|
918
|
+
for (const [knownProviderID, knownProvider] of Object.entries(
|
|
919
|
+
s.providers
|
|
920
|
+
)) {
|
|
921
|
+
if (knownProvider.info.models[fullModelKey]) {
|
|
922
|
+
suggestion = `Did you mean: ${knownProviderID}/${fullModelKey}?`;
|
|
923
|
+
break;
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
throw new ModelNotFoundError({ providerID, modelID, suggestion });
|
|
928
|
+
}
|
|
913
929
|
|
|
914
930
|
// For synthetic providers (like link-assistant/echo and link-assistant/cache), skip SDK loading
|
|
915
931
|
// These providers have a custom getModel function that creates the model directly
|
|
@@ -1077,6 +1093,7 @@ export namespace Provider {
|
|
|
1077
1093
|
z.object({
|
|
1078
1094
|
providerID: z.string(),
|
|
1079
1095
|
modelID: z.string(),
|
|
1096
|
+
suggestion: z.string().optional(),
|
|
1080
1097
|
})
|
|
1081
1098
|
);
|
|
1082
1099
|
|
package/src/session/index.ts
CHANGED
|
@@ -580,6 +580,27 @@ export namespace Session {
|
|
|
580
580
|
metadata: z.custom<ProviderMetadata>().optional(),
|
|
581
581
|
}),
|
|
582
582
|
(input) => {
|
|
583
|
+
// Handle undefined or null usage gracefully
|
|
584
|
+
// Some providers (e.g., OpenCode with Kimi K2.5) may return incomplete usage data
|
|
585
|
+
// See: https://github.com/link-assistant/agent/issues/152
|
|
586
|
+
if (!input.usage) {
|
|
587
|
+
log.warn(() => ({
|
|
588
|
+
message: 'getUsage received undefined usage, returning zero values',
|
|
589
|
+
providerMetadata: input.metadata
|
|
590
|
+
? JSON.stringify(input.metadata)
|
|
591
|
+
: 'none',
|
|
592
|
+
}));
|
|
593
|
+
return {
|
|
594
|
+
cost: 0,
|
|
595
|
+
tokens: {
|
|
596
|
+
input: 0,
|
|
597
|
+
output: 0,
|
|
598
|
+
reasoning: 0,
|
|
599
|
+
cache: { read: 0, write: 0 },
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
583
604
|
// Log raw usage data in verbose mode for debugging
|
|
584
605
|
if (Flag.OPENCODE_VERBOSE) {
|
|
585
606
|
log.debug(() => ({
|
package/src/session/processor.ts
CHANGED
|
@@ -219,9 +219,17 @@ export namespace SessionProcessor {
|
|
|
219
219
|
break;
|
|
220
220
|
|
|
221
221
|
case 'finish-step':
|
|
222
|
+
// Safely handle missing or undefined usage data
|
|
223
|
+
// Some providers (e.g., OpenCode with Kimi K2.5) may return incomplete usage
|
|
224
|
+
// See: https://github.com/link-assistant/agent/issues/152
|
|
225
|
+
const safeUsage = value.usage ?? {
|
|
226
|
+
inputTokens: 0,
|
|
227
|
+
outputTokens: 0,
|
|
228
|
+
totalTokens: 0,
|
|
229
|
+
};
|
|
222
230
|
const usage = Session.getUsage({
|
|
223
231
|
model: input.model,
|
|
224
|
-
usage:
|
|
232
|
+
usage: safeUsage,
|
|
225
233
|
metadata: value.providerMetadata,
|
|
226
234
|
});
|
|
227
235
|
// Use toFinishReason to safely convert object/string finishReason to string
|
|
@@ -322,6 +330,34 @@ export namespace SessionProcessor {
|
|
|
322
330
|
}
|
|
323
331
|
} catch (e) {
|
|
324
332
|
log.error(() => ({ message: 'process', error: e }));
|
|
333
|
+
|
|
334
|
+
// Check for AI SDK usage-related TypeError (input_tokens undefined)
|
|
335
|
+
// This happens when providers return incomplete usage data
|
|
336
|
+
// See: https://github.com/link-assistant/agent/issues/152
|
|
337
|
+
if (
|
|
338
|
+
e instanceof TypeError &&
|
|
339
|
+
(e.message.includes('input_tokens') ||
|
|
340
|
+
e.message.includes('output_tokens') ||
|
|
341
|
+
e.message.includes("reading 'input_tokens'") ||
|
|
342
|
+
e.message.includes("reading 'output_tokens'"))
|
|
343
|
+
) {
|
|
344
|
+
log.warn(() => ({
|
|
345
|
+
message:
|
|
346
|
+
'Provider returned invalid usage data, continuing with zero usage',
|
|
347
|
+
errorMessage: e.message,
|
|
348
|
+
providerID: input.providerID,
|
|
349
|
+
}));
|
|
350
|
+
// Set default token values to prevent crash
|
|
351
|
+
input.assistantMessage.tokens = {
|
|
352
|
+
input: 0,
|
|
353
|
+
output: 0,
|
|
354
|
+
reasoning: 0,
|
|
355
|
+
cache: { read: 0, write: 0 },
|
|
356
|
+
};
|
|
357
|
+
// Continue processing instead of failing
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
325
361
|
const error = MessageV2.fromError(e, {
|
|
326
362
|
providerID: input.providerID,
|
|
327
363
|
});
|