feat(core): update Copilot for token-based billing (#30181)
This commit is contained in:
@@ -14,6 +14,7 @@ export function adapterState() {
|
||||
currentTextID: undefined as string | undefined,
|
||||
currentReasoningID: undefined as string | undefined,
|
||||
toolNames: {} as Record<string, string>,
|
||||
copilotTotalNanoAiu: undefined as number | undefined,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +27,20 @@ function providerMetadata(value: unknown): ProviderMetadata | undefined {
|
||||
return Schema.is(ProviderMetadata)(value) ? value : undefined
|
||||
}
|
||||
|
||||
// Temporary AI SDK bridge: Copilot billing survives only in raw provider chunks here.
|
||||
// Move this extraction into @opencode-ai/llm when Copilot is handled by the native runtime.
|
||||
function copilotTotalNanoAiu(value: unknown) {
|
||||
if (!value || typeof value !== "object") return
|
||||
const raw = value as Record<string, unknown>
|
||||
const response =
|
||||
raw.response && typeof raw.response === "object" ? (raw.response as Record<string, unknown>) : undefined
|
||||
const usage = raw.copilot_usage ?? response?.copilot_usage
|
||||
if (!usage || typeof usage !== "object") return
|
||||
const total = (usage as Record<string, unknown>).total_nano_aiu
|
||||
if (typeof total !== "number" || !Number.isFinite(total) || total < 0) return
|
||||
return total
|
||||
}
|
||||
|
||||
function usage(value: unknown) {
|
||||
if (!value || typeof value !== "object") return undefined
|
||||
const item = value as {
|
||||
@@ -70,14 +85,28 @@ export function toLLMEvents(
|
||||
return Effect.succeed([LLMEvent.stepStart({ index: state.step })])
|
||||
|
||||
case "finish-step":
|
||||
return Effect.sync(() => [
|
||||
LLMEvent.stepFinish({
|
||||
index: state.step++,
|
||||
reason: finishReason(event.finishReason),
|
||||
usage: usage(event.usage),
|
||||
providerMetadata: providerMetadata(event.providerMetadata),
|
||||
}),
|
||||
])
|
||||
return Effect.sync(() => {
|
||||
const original = providerMetadata(event.providerMetadata)
|
||||
const metadata =
|
||||
state.copilotTotalNanoAiu === undefined
|
||||
? original
|
||||
: {
|
||||
...original,
|
||||
copilot: {
|
||||
...original?.copilot,
|
||||
totalNanoAiu: state.copilotTotalNanoAiu,
|
||||
},
|
||||
}
|
||||
state.copilotTotalNanoAiu = undefined
|
||||
return [
|
||||
LLMEvent.stepFinish({
|
||||
index: state.step++,
|
||||
reason: finishReason(event.finishReason),
|
||||
usage: usage(event.usage),
|
||||
providerMetadata: metadata,
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
case "finish":
|
||||
return Effect.sync(() => {
|
||||
@@ -238,11 +267,16 @@ export function toLLMEvents(
|
||||
case "abort":
|
||||
case "source":
|
||||
case "file":
|
||||
case "raw":
|
||||
case "tool-output-denied":
|
||||
case "tool-approval-request":
|
||||
return Effect.succeed([])
|
||||
|
||||
case "raw":
|
||||
return Effect.sync(() => {
|
||||
state.copilotTotalNanoAiu = copilotTotalNanoAiu(event.rawValue) ?? state.copilotTotalNanoAiu
|
||||
return []
|
||||
})
|
||||
|
||||
default: {
|
||||
const _exhaustive: never = event
|
||||
void _exhaustive
|
||||
|
||||
Reference in New Issue
Block a user