@agentfield/sdk 0.1.142-rc.8 → 0.1.142-rc.9
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/dist/index.d.ts +9 -1
- package/dist/index.js +66 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -354,6 +354,7 @@ declare class AIClient {
|
|
|
354
354
|
resolveModelChoice(options?: AIRequestOptions): {
|
|
355
355
|
provider: NonNullable<AIConfig['provider']>;
|
|
356
356
|
modelName: string;
|
|
357
|
+
routingProvider: string;
|
|
357
358
|
};
|
|
358
359
|
private buildModel;
|
|
359
360
|
private buildPrompt;
|
|
@@ -609,6 +610,8 @@ declare const USAGE_ENVELOPE_KEY = "__agentfield_usage__";
|
|
|
609
610
|
/** A single LLM (or harness) call usage record. */
|
|
610
611
|
interface CostEntry {
|
|
611
612
|
model: string;
|
|
613
|
+
usageStatus?: 'missing';
|
|
614
|
+
routingProvider?: string;
|
|
612
615
|
inputTokens: number;
|
|
613
616
|
outputTokens: number;
|
|
614
617
|
totalTokens: number;
|
|
@@ -632,6 +635,8 @@ interface CostEntry {
|
|
|
632
635
|
/** Input accepted by {@link CostTracker.record}. */
|
|
633
636
|
interface CostEntryInit {
|
|
634
637
|
model: string;
|
|
638
|
+
usageStatus?: 'missing';
|
|
639
|
+
routingProvider?: string;
|
|
635
640
|
inputTokens?: number;
|
|
636
641
|
outputTokens?: number;
|
|
637
642
|
totalTokens?: number;
|
|
@@ -646,6 +651,8 @@ interface CostEntryInit {
|
|
|
646
651
|
}
|
|
647
652
|
/** Wire form of a single usage entry (snake_case cross-language contract). */
|
|
648
653
|
interface UsageEntryWire {
|
|
654
|
+
usage_status?: 'missing';
|
|
655
|
+
routing_provider?: string;
|
|
649
656
|
source: string;
|
|
650
657
|
provider: string | null;
|
|
651
658
|
model: string;
|
|
@@ -1211,6 +1218,7 @@ declare function buildToolConfig(toolsParam: ToolsOption, agent: Agent): Promise
|
|
|
1211
1218
|
declare function executeToolCallLoop(agent: Agent, prompt: string, toolMap: ToolSet, config: ToolCallConfig, needsLazyHydration: boolean, buildModel: () => any, options?: AIRequestOptions, modelChoice?: {
|
|
1212
1219
|
provider?: string;
|
|
1213
1220
|
modelName?: string;
|
|
1221
|
+
routingProvider?: string;
|
|
1214
1222
|
}): Promise<{
|
|
1215
1223
|
text: string;
|
|
1216
1224
|
trace: ToolCallTrace;
|
|
@@ -1959,7 +1967,7 @@ declare const PROVIDER_SPECS: {
|
|
|
1959
1967
|
};
|
|
1960
1968
|
};
|
|
1961
1969
|
type HarnessProviderName = keyof typeof PROVIDER_SPECS;
|
|
1962
|
-
declare const SUPPORTED_PROVIDER_NAMES: readonly ("aforge" | "claude-code" | "codex" | "
|
|
1970
|
+
declare const SUPPORTED_PROVIDER_NAMES: readonly ("gemini" | "aforge" | "claude-code" | "codex" | "opencode" | "pi" | "omp")[];
|
|
1963
1971
|
interface ProviderHealth {
|
|
1964
1972
|
provider: HarnessProviderName;
|
|
1965
1973
|
binary: string | null;
|
package/dist/index.js
CHANGED
|
@@ -2750,6 +2750,8 @@ var CostTracker = class {
|
|
|
2750
2750
|
record(init) {
|
|
2751
2751
|
this.entries.push({
|
|
2752
2752
|
model: init.model,
|
|
2753
|
+
usageStatus: init.usageStatus,
|
|
2754
|
+
routingProvider: init.routingProvider,
|
|
2753
2755
|
inputTokens: toCount(init.inputTokens),
|
|
2754
2756
|
outputTokens: toCount(init.outputTokens),
|
|
2755
2757
|
totalTokens: toCount(init.totalTokens),
|
|
@@ -2809,6 +2811,8 @@ var CostTracker = class {
|
|
|
2809
2811
|
cost_usd: e.costUsd,
|
|
2810
2812
|
cost_source: e.costSource
|
|
2811
2813
|
});
|
|
2814
|
+
if (e.routingProvider) entries[entries.length - 1].routing_provider = e.routingProvider;
|
|
2815
|
+
if (e.usageStatus) entries[entries.length - 1].usage_status = e.usageStatus;
|
|
2812
2816
|
totalInput += e.inputTokens;
|
|
2813
2817
|
totalOutput += e.outputTokens;
|
|
2814
2818
|
totalTokens += entryTotal;
|
|
@@ -2937,7 +2941,19 @@ function recordAiSdkUsage(params) {
|
|
|
2937
2941
|
const tokens = extractTokenUsage(params.source.totalUsage ?? params.source.usage);
|
|
2938
2942
|
const cost = extractProviderCostUsd(params.source);
|
|
2939
2943
|
const hasTokens = tokens.inputTokens > 0 || tokens.outputTokens > 0 || tokens.totalTokens > 0 || tokens.cacheReadTokens > 0 || tokens.cacheCreationTokens > 0;
|
|
2940
|
-
|
|
2944
|
+
const receipt = params.source.totalUsage ?? params.source.usage;
|
|
2945
|
+
const hasTokenReceipt = isRecord(receipt) && ["inputTokens", "outputTokens", "totalTokens"].some(
|
|
2946
|
+
(key) => typeof receipt[key] === "number" && Number.isFinite(receipt[key])
|
|
2947
|
+
);
|
|
2948
|
+
if (!hasTokens && cost === null && !hasTokenReceipt) {
|
|
2949
|
+
tracker.record({
|
|
2950
|
+
model: params.model,
|
|
2951
|
+
provider: params.provider ?? "unknown",
|
|
2952
|
+
routingProvider: params.routingProvider ?? params.provider ?? "unknown",
|
|
2953
|
+
usageStatus: "missing"
|
|
2954
|
+
});
|
|
2955
|
+
return;
|
|
2956
|
+
}
|
|
2941
2957
|
tracker.record({
|
|
2942
2958
|
model: params.model,
|
|
2943
2959
|
...tokens,
|
|
@@ -2945,6 +2961,7 @@ function recordAiSdkUsage(params) {
|
|
|
2945
2961
|
costSource: cost !== null ? "provider" : null,
|
|
2946
2962
|
reasonerName: params.reasonerName !== void 0 ? params.reasonerName : current?.metadata.reasonerId ?? null,
|
|
2947
2963
|
source: "llm",
|
|
2964
|
+
routingProvider: params.routingProvider ?? params.provider ?? void 0,
|
|
2948
2965
|
provider: params.provider ?? void 0
|
|
2949
2966
|
});
|
|
2950
2967
|
} catch {
|
|
@@ -3175,7 +3192,7 @@ async function executeToolCallLoop(agent, prompt, toolMap, config, needsLazyHydr
|
|
|
3175
3192
|
const usageModel = modelChoice?.modelName ?? options.model;
|
|
3176
3193
|
const recordLoopUsage = (result2) => {
|
|
3177
3194
|
if (usageModel) {
|
|
3178
|
-
recordAiSdkUsage({ source: result2, model: usageModel, provider: modelChoice?.provider });
|
|
3195
|
+
recordAiSdkUsage({ source: result2, model: usageModel, provider: modelChoice?.provider, routingProvider: modelChoice?.routingProvider });
|
|
3179
3196
|
}
|
|
3180
3197
|
};
|
|
3181
3198
|
const trace = {
|
|
@@ -3700,6 +3717,26 @@ function withOpenRouterUsageInclude(baseFetch) {
|
|
|
3700
3717
|
return impl(input, init);
|
|
3701
3718
|
};
|
|
3702
3719
|
}
|
|
3720
|
+
|
|
3721
|
+
// src/usage/routingProvider.ts
|
|
3722
|
+
function routingProvider(provider, endpoint) {
|
|
3723
|
+
if (endpoint !== void 0 && endpoint !== null) {
|
|
3724
|
+
try {
|
|
3725
|
+
const url = new URL(endpoint);
|
|
3726
|
+
if (!["https:", "http:"].includes(url.protocol)) return "unknown";
|
|
3727
|
+
const host = url.hostname.toLowerCase();
|
|
3728
|
+
if (host === "openrouter.ai") return "openrouter";
|
|
3729
|
+
if (host === "api.openai.com") return "openai";
|
|
3730
|
+
if (host === "api.anthropic.com") return "anthropic";
|
|
3731
|
+
if (host === "generativelanguage.googleapis.com") return "google";
|
|
3732
|
+
return "other";
|
|
3733
|
+
} catch {
|
|
3734
|
+
return "unknown";
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
const normalized = provider === "gemini" ? "google" : provider?.toLowerCase();
|
|
3738
|
+
return ["openrouter", "openai", "anthropic", "google", "bedrock", "azure", "ollama"].includes(normalized ?? "") ? normalized : "unknown";
|
|
3739
|
+
}
|
|
3703
3740
|
var IMAGE_MIME_TYPES = {
|
|
3704
3741
|
".jpg": "image/jpeg",
|
|
3705
3742
|
".jpeg": "image/jpeg",
|
|
@@ -4024,7 +4061,7 @@ var AIClient = class {
|
|
|
4024
4061
|
};
|
|
4025
4062
|
}
|
|
4026
4063
|
async generate(prompt, options = {}) {
|
|
4027
|
-
const { provider, modelName } = this.resolveModelChoice(options);
|
|
4064
|
+
const { provider, modelName, routingProvider: routingProvider2 } = this.resolveModelChoice(options);
|
|
4028
4065
|
const model = this.buildModel(options);
|
|
4029
4066
|
const requestPrompt = this.buildPrompt(prompt, options.content);
|
|
4030
4067
|
if (options.schema) {
|
|
@@ -4040,7 +4077,7 @@ var AIClient = class {
|
|
|
4040
4077
|
experimental_repairText: async ({ text: text2 }) => repairJsonText(text2)
|
|
4041
4078
|
});
|
|
4042
4079
|
const response2 = await this.withRateLimitRetry(call2);
|
|
4043
|
-
recordAiSdkUsage({ source: response2, model: modelName, provider });
|
|
4080
|
+
recordAiSdkUsage({ source: response2, model: modelName, provider, routingProvider: routingProvider2 });
|
|
4044
4081
|
return response2.object;
|
|
4045
4082
|
}
|
|
4046
4083
|
const call = async () => generateText({
|
|
@@ -4051,23 +4088,38 @@ var AIClient = class {
|
|
|
4051
4088
|
maxOutputTokens: options.maxTokens ?? this.config.maxTokens
|
|
4052
4089
|
});
|
|
4053
4090
|
const response = await this.withRateLimitRetry(call);
|
|
4054
|
-
recordAiSdkUsage({ source: response, model: modelName, provider });
|
|
4091
|
+
recordAiSdkUsage({ source: response, model: modelName, provider, routingProvider: routingProvider2 });
|
|
4055
4092
|
return response.text;
|
|
4056
4093
|
}
|
|
4057
|
-
//
|
|
4058
|
-
//
|
|
4059
|
-
// stream": attaching to them would force full background consumption of a
|
|
4060
|
-
// stream the caller may abandon early, changing stream semantics.
|
|
4094
|
+
// Observe usage only after the caller consumes the stream. Merely creating
|
|
4095
|
+
// the stream must not start background consumption of an abandoned response.
|
|
4061
4096
|
async stream(prompt, options = {}) {
|
|
4062
|
-
const
|
|
4097
|
+
const { provider, modelName, routingProvider: routingProvider2 } = this.resolveModelChoice(options);
|
|
4098
|
+
const tracker = ExecutionContext.getCurrent()?.costTracker;
|
|
4063
4099
|
const streamResult = streamText({
|
|
4064
|
-
model,
|
|
4100
|
+
model: this.buildModel(options),
|
|
4065
4101
|
prompt: this.buildPrompt(prompt, options.content),
|
|
4066
4102
|
system: options.system,
|
|
4067
4103
|
temperature: options.temperature ?? this.config.temperature,
|
|
4068
4104
|
maxOutputTokens: options.maxTokens ?? this.config.maxTokens
|
|
4069
4105
|
});
|
|
4070
|
-
return streamResult.textStream;
|
|
4106
|
+
if (!tracker) return streamResult.textStream;
|
|
4107
|
+
return (async function* () {
|
|
4108
|
+
let completed = false;
|
|
4109
|
+
try {
|
|
4110
|
+
for await (const text2 of streamResult.textStream) yield text2;
|
|
4111
|
+
try {
|
|
4112
|
+
const usage = await streamResult.totalUsage;
|
|
4113
|
+
if (usage) recordAiSdkUsage({ source: { totalUsage: usage }, model: modelName, provider, routingProvider: routingProvider2, tracker });
|
|
4114
|
+
else tracker.record({ model: modelName, provider, routingProvider: routingProvider2, usageStatus: "missing" });
|
|
4115
|
+
} catch {
|
|
4116
|
+
tracker.record({ model: modelName, provider, routingProvider: routingProvider2, usageStatus: "missing" });
|
|
4117
|
+
}
|
|
4118
|
+
completed = true;
|
|
4119
|
+
} finally {
|
|
4120
|
+
if (!completed) tracker.record({ model: modelName, provider, routingProvider: routingProvider2, usageStatus: "missing" });
|
|
4121
|
+
}
|
|
4122
|
+
})();
|
|
4071
4123
|
}
|
|
4072
4124
|
async embed(value, options = {}) {
|
|
4073
4125
|
const model = this.buildEmbeddingModel(options);
|
|
@@ -4104,7 +4156,8 @@ var AIClient = class {
|
|
|
4104
4156
|
resolveModelChoice(options = {}) {
|
|
4105
4157
|
return {
|
|
4106
4158
|
provider: options.provider ?? this.config.provider ?? "openai",
|
|
4107
|
-
modelName: options.model ?? this.config.model ?? "gpt-4o"
|
|
4159
|
+
modelName: options.model ?? this.config.model ?? "gpt-4o",
|
|
4160
|
+
routingProvider: routingProvider(options.provider ?? this.config.provider ?? "openai", this.config.baseUrl)
|
|
4108
4161
|
};
|
|
4109
4162
|
}
|
|
4110
4163
|
buildModel(options) {
|