@alvin0/ai-agent-sdk-core 0.1.3 → 0.1.4

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.
Files changed (63) hide show
  1. package/dist/agent/accounting/ledger.js +1 -1
  2. package/dist/agent/accounting/ledger.js.map +1 -1
  3. package/dist/agent/accounting/report.d.ts +1 -1
  4. package/dist/agent/define/definition.d.ts +26 -5
  5. package/dist/agent/define/definition.d.ts.map +1 -1
  6. package/dist/agent/define/definition.js +1 -1
  7. package/dist/agent/define/definition.js.map +1 -1
  8. package/dist/agent/define/session/accounting.js +1 -1
  9. package/dist/agent/define/session/accounting.js.map +1 -1
  10. package/dist/agent/define/session/model-config.js +1 -1
  11. package/dist/agent/define/session/model-config.js.map +1 -1
  12. package/dist/agent/define/session/types.d.ts +0 -3
  13. package/dist/agent/define/session/types.d.ts.map +1 -1
  14. package/dist/agent/loop/turn/config.js +1 -1
  15. package/dist/agent/loop/turn/config.js.map +1 -1
  16. package/dist/agent/memory/compaction.d.ts.map +1 -1
  17. package/dist/agent/memory/compaction.js +1 -1
  18. package/dist/agent/memory/compaction.js.map +1 -1
  19. package/dist/composition/agent/definition.js +1 -1
  20. package/dist/composition/agent/definition.js.map +1 -1
  21. package/dist/composition/agent/options.js +1 -1
  22. package/dist/composition/agent/options.js.map +1 -1
  23. package/dist/composition/agent/session.js +1 -1
  24. package/dist/composition/agent/session.js.map +1 -1
  25. package/dist/composition/agent/types.d.ts +11 -10
  26. package/dist/composition/agent/types.d.ts.map +1 -1
  27. package/dist/composition/runtime/owner.js +1 -1
  28. package/dist/composition/runtime/owner.js.map +1 -1
  29. package/dist/composition/runtime/types.d.ts +7 -1
  30. package/dist/composition/runtime/types.d.ts.map +1 -1
  31. package/dist/contract/adapter.d.ts +1 -1
  32. package/dist/contract/call-config.d.ts +8 -1
  33. package/dist/contract/call-config.d.ts.map +1 -1
  34. package/dist/contract/call-config.js +1 -1
  35. package/dist/contract/call-config.js.map +1 -1
  36. package/dist/contract/generate-options.d.ts +5 -0
  37. package/dist/contract/generate-options.d.ts.map +1 -1
  38. package/dist/contract/model-info.d.ts +26 -7
  39. package/dist/contract/model-info.d.ts.map +1 -1
  40. package/dist/errors/model-error.d.ts +0 -1
  41. package/dist/errors/model-error.d.ts.map +1 -1
  42. package/dist/errors/model-error.js +1 -1
  43. package/dist/errors/model-error.js.map +1 -1
  44. package/dist/index.d.ts +3 -3
  45. package/dist/observability/bus.js +1 -1
  46. package/dist/observation/report.d.ts +11 -0
  47. package/dist/observation/report.d.ts.map +1 -1
  48. package/dist/observation/report.js.map +1 -1
  49. package/dist/primitives/version.d.ts +1 -1
  50. package/dist/primitives/version.js +1 -1
  51. package/dist/primitives/version.js.map +1 -1
  52. package/dist/provider.d.ts +1 -1
  53. package/dist/runtime/model-call-handle.js +1 -1
  54. package/dist/runtime/model-call-handle.js.map +1 -1
  55. package/dist/runtime/model-metadata.js +1 -1
  56. package/dist/runtime/model-metadata.js.map +1 -1
  57. package/dist/runtime/model-stream.js +1 -1
  58. package/dist/runtime/model-stream.js.map +1 -1
  59. package/dist/runtime/registry.d.ts +7 -1
  60. package/dist/runtime/registry.d.ts.map +1 -1
  61. package/dist/runtime/registry.js +1 -1
  62. package/dist/runtime/registry.js.map +1 -1
  63. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"model-call-handle.js","names":[],"sources":["../../src/runtime/model-call-handle.ts"],"sourcesContent":["import type { GenerateOptions } from '../contract/generate-options.ts'\nimport { deepFreeze } from '../primitives/freeze.ts'\nimport type { JsonObject } from '../primitives/json.ts'\nimport type { StreamChunk, TokenUsage } from '../stream/chunk.ts'\nimport { createObservationRunScope, createOperationId, isSpanId, isTraceId, type CorrelationContext, type ObservationRunScope } from '../observation/context.ts'\nimport { safeErrorRecord, type ObservationEvent, type ObservationResource, type OperationStatus, type SafeErrorRecord } from '../observation/event.ts'\nimport { createCoreSpan, disabledDeliverySummary, NOOP_OBSERVATION_PORT, snapshotObservationSpan, validateCaptureReceipt, type CaptureReceipt, type DeliveryMode, type ObservationBoundary, type ObservationDeliverySummary, type ObservationPort, type ObservationSpan } from '../observation/port.ts'\nimport { AgentSdkError } from '../errors/agent-sdk-error.ts'\nimport { ModelCallObservationError, OBSERVATION_ERROR_CODES, type EndProviderAttemptInput, type ModelCallHandle, type ModelCallReport, type ModelInvocationContext, type ProviderAttemptHandle, type ProviderRetryScheduledInput, type StartProviderAttemptInput } from '../observation/report.ts'\nimport { addUsageCounters, classifyUsageCoverage, possiblyBilledAttemptsWithoutUsage, validateUsageCounters, type AttemptUsageReport, type UsageCoverage } from '../observation/usage.ts'\n\nconst scopes = new WeakMap<object, Map<string, ObservationRunScope>>()\n\nfunction nowMonotonic(): number {\n return globalThis.performance?.now() ?? Date.now()\n}\n\nfunction scopeFor(key: object, runId: string, supplied?: ObservationRunScope): ObservationRunScope {\n if (supplied !== undefined) return supplied\n let runs = scopes.get(key)\n if (!runs) {\n runs = new Map()\n scopes.set(key, runs)\n }\n let scope = runs.get(runId)\n if (!scope) {\n scope = createObservationRunScope()\n runs.set(runId, scope)\n }\n return scope\n}\n\nfunction safeFailureFromFinish(\n chunk: Extract<StreamChunk, { type: 'finish' }>,\n isRetryable?: (code: string) => boolean,\n): SafeErrorRecord | undefined {\n if (chunk.reason.kind !== 'error' && chunk.reason.kind !== 'aborted') return undefined\n const failure = chunk.reason.failure\n return Object.freeze({\n type: 'ModelError',\n message: chunk.reason.kind === 'aborted'\n ? 'model call was aborted; inspect the stable code for classification'\n : 'model call failed; inspect the stable code and provider request ID',\n code: failure.code,\n ...isRetryable === undefined ? {} : { retryable: isRetryable(failure.code) },\n ...failure.status === undefined ? {} : { status: failure.status },\n })\n}\n\nfunction boundaryRank(boundary: ObservationBoundary): number {\n if (boundary === 'remote-acknowledged') return 2\n if (boundary === 'local-durable') return 1\n return 0\n}\n\ninterface DeliveryTracker {\n accepted: number\n rejected: number\n pending: number\n reached: ObservationBoundary\n lastFailure?: SafeErrorRecord\n}\n\nfunction applyReceipt(tracker: DeliveryTracker, receipt: CaptureReceipt, critical: boolean): void {\n if (!critical) return\n if (receipt.status === 'accepted') tracker.accepted += 1\n else tracker.rejected += 1\n if (receipt.status === 'accepted' && boundaryRank(receipt.boundary) > boundaryRank(tracker.reached)) tracker.reached = receipt.boundary\n}\n\nfunction deliverySummary(port: ObservationPort, mode: DeliveryMode, tracker: DeliveryTracker): ObservationDeliverySummary {\n if (port === NOOP_OBSERVATION_PORT) return disabledDeliverySummary()\n const requiredBoundary: ObservationBoundary = mode === 'operational'\n ? 'none'\n : boundaryRank(tracker.reached) > 0 ? tracker.reached : 'local-durable'\n return deepFreeze({\n mode,\n requiredBoundary,\n reachedBoundary: tracker.reached,\n complete: tracker.rejected === 0 && tracker.pending === 0\n && boundaryRank(tracker.reached) >= boundaryRank(requiredBoundary),\n acceptedCritical: tracker.accepted,\n rejectedCritical: tracker.rejected,\n pendingCritical: tracker.pending,\n ...tracker.lastFailure === undefined ? {} : { lastFailure: tracker.lastFailure },\n })\n}\n\nfunction validParent(value: Partial<CorrelationContext> | undefined): CorrelationContext | undefined {\n if (!value || !isTraceId(value.traceId) || !isSpanId(value.spanId)\n || typeof value.runId !== 'string' || value.runId.length === 0) return undefined\n return {\n traceId: value.traceId,\n spanId: value.spanId,\n parentSpanId: value.parentSpanId === null || isSpanId(value.parentSpanId) ? value.parentSpanId : null,\n runId: value.runId,\n ...value.conversationId === undefined ? {} : { conversationId: value.conversationId },\n ...value.turnId === undefined ? {} : { turnId: value.turnId },\n ...value.modelCallId === undefined ? {} : { modelCallId: value.modelCallId },\n ...value.attemptId === undefined ? {} : { attemptId: value.attemptId },\n ...value.toolCallId === undefined ? {} : { toolCallId: value.toolCallId },\n ...value.providerRequestId === undefined ? {} : { providerRequestId: value.providerRequestId },\n ...value.sessionId === undefined ? {} : { sessionId: value.sessionId },\n }\n}\n\nfunction openContainedSpan(port: ObservationPort, input: Parameters<ObservationPort['openSpan']>[0], tracker: DeliveryTracker): ObservationSpan {\n try {\n const span = snapshotObservationSpan(port.openSpan(input))\n if (span && span.correlation.runId === input.runId\n && span.correlation.modelCallId === input.correlation?.modelCallId) {\n let ended = false\n return Object.freeze({\n correlation: span.correlation,\n traceparent: span.traceparent,\n end(status: OperationStatus, endedAt: string, monotonicMs: number): void {\n if (ended) return\n ended = true\n try { span.end(status, endedAt, monotonicMs) } catch (error) { tracker.lastFailure = safeErrorRecord(error) }\n },\n })\n }\n tracker.lastFailure = Object.freeze({\n type: 'ObservationSpanError',\n message: 'observation backend returned an invalid or mismatched span identity',\n code: OBSERVATION_ERROR_CODES.OTEL_PROVIDER_UNCONFIGURED,\n })\n } catch (error) {\n tracker.lastFailure = safeErrorRecord(error)\n }\n return createCoreSpan(input)\n}\n\nexport interface CreateModelCallHandleOptions {\n readonly options: GenerateOptions\n readonly providerFamily?: string\n readonly providerPluginId?: string\n readonly isRetryable?: (code: string) => boolean\n readonly context?: ModelInvocationContext\n readonly defaultObservation?: ObservationPort\n readonly resource: ObservationResource\n readonly routePresent: boolean\n readonly dispatchState: () => 'not-sent' | 'unknown'\n readonly stream: (context: ModelInvocationContext) => AsyncIterable<StreamChunk>\n}\n\nexport function createModelCallHandle(input: CreateModelCallHandleOptions): ModelCallHandle {\n const contextKey = input.context ?? {}\n const supplied = input.context?.correlation\n const runId = typeof supplied?.runId === 'string' && supplied.runId.length > 0 ? supplied.runId : createOperationId()\n const modelCallId = typeof supplied?.modelCallId === 'string' && supplied.modelCallId.length > 0 ? supplied.modelCallId : createOperationId()\n const scope = scopeFor(contextKey, runId, input.context?.scope)\n const startedAt = new Date().toISOString()\n const startedMonotonic = nowMonotonic()\n const port = input.context?.observation ?? input.defaultObservation ?? NOOP_OBSERVATION_PORT\n const tracker: DeliveryTracker = { accepted: 0, rejected: 0, pending: 0, reached: 'none' }\n let mode: DeliveryMode = 'operational'\n try {\n const configuredMode = port.mode\n if (configuredMode !== 'operational' && configuredMode !== 'reliable' && configuredMode !== 'audit') {\n throw new TypeError('observation delivery mode is invalid')\n }\n mode = configuredMode\n } catch (modeError) {\n tracker.lastFailure = safeErrorRecord(modeError)\n }\n const parent = validParent(supplied)\n const span = openContainedSpan(port, {\n name: 'sdk.model.call',\n runId,\n ...(parent === undefined ? {} : { parent }),\n correlation: {\n modelCallId,\n ...supplied?.conversationId === undefined ? {} : { conversationId: supplied.conversationId },\n ...supplied?.turnId === undefined ? {} : { turnId: supplied.turnId },\n ...supplied?.sessionId === undefined ? {} : { sessionId: supplied.sessionId },\n },\n startedAt,\n monotonicMs: scope.monotonicMs(),\n }, tracker)\n const makeEvent = (phase: 'start' | 'end', data: JsonObject): ObservationEvent<'sdk.model.call'> => deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.model.call',\n phase,\n occurredAt: new Date().toISOString(),\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: span.correlation,\n data,\n })\n\n const capture = (event: ObservationEvent): void => {\n try {\n const receipt = validateCaptureReceipt(port.capture(event), event.eventId)\n applyReceipt(tracker, receipt, event.priority === 'critical')\n } catch (error) {\n tracker.rejected += event.priority === 'critical' ? 1 : 0\n tracker.lastFailure = safeErrorRecord(error)\n }\n }\n\n const attempts: AttemptUsageReport[] = []\n const openAttempts = new Set<(input: EndProviderAttemptInput) => AttemptUsageReport>()\n let nextAttemptNumber = 1\n let providerAttemptAccountingDeclared = false\n\n function recordProviderRetry(retry: ProviderRetryScheduledInput): void {\n capture(deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.retry.scheduled',\n phase: 'point',\n occurredAt: new Date().toISOString(),\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: span.correlation,\n data: {\n nextAttemptNumber: retry.nextAttemptNumber,\n delayMs: retry.delayMs,\n failureCode: retry.failureCode,\n },\n }))\n }\n\n async function startProviderAttempt(\n attemptInput: StartProviderAttemptInput,\n signal?: AbortSignal,\n ): Promise<ProviderAttemptHandle> {\n const attemptNumber = nextAttemptNumber++\n const attemptId = createOperationId()\n const attemptStartedAt = new Date().toISOString()\n const attemptStartedMonotonic = nowMonotonic()\n const attemptSpan = openContainedSpan(port, {\n name: 'sdk.provider.attempt',\n runId,\n parent: span.correlation,\n correlation: { modelCallId, attemptId },\n startedAt: attemptStartedAt,\n monotonicMs: scope.monotonicMs(),\n }, tracker)\n const startEvent: ObservationEvent<'sdk.provider.attempt'> = deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.attempt',\n phase: 'start',\n occurredAt: attemptStartedAt,\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: attemptSpan.correlation,\n data: {\n provider: attemptInput.provider,\n model: attemptInput.model,\n attemptNumber,\n method: attemptInput.method,\n origin: attemptInput.origin,\n dispatchState: 'not-sent',\n },\n })\n\n if (mode === 'audit') {\n tracker.pending += 1\n try {\n const rawReceipt = port.checkpoint\n ? await port.checkpoint(startEvent, signal)\n : Object.freeze({\n eventId: startEvent.eventId,\n status: 'rejected' as const,\n durable: false,\n boundary: 'none' as const,\n reason: 'exporter-unavailable' as const,\n })\n const receipt = validateCaptureReceipt(rawReceipt, startEvent.eventId)\n tracker.pending -= 1\n applyReceipt(tracker, receipt, true)\n if (receipt.status !== 'accepted' || !receipt.durable) {\n if (receipt.status === 'accepted') tracker.rejected += 1\n tracker.lastFailure = Object.freeze({\n type: 'ObservationCheckpointError',\n message: `provider-attempt audit checkpoint was ${receipt.status}`,\n code: OBSERVATION_ERROR_CODES.CAPTURE_REJECTED,\n })\n attemptSpan.end('rejected', new Date().toISOString(), scope.monotonicMs())\n throw new AgentSdkError(\n 'audit observation is unavailable before provider dispatch',\n OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE,\n )\n }\n } catch (checkpointError) {\n if (tracker.pending > 0) tracker.pending -= 1\n if (!(checkpointError instanceof AgentSdkError\n && checkpointError.code === OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE)) {\n tracker.rejected += 1\n tracker.lastFailure = safeErrorRecord(checkpointError)\n attemptSpan.end('rejected', new Date().toISOString(), scope.monotonicMs())\n }\n throw checkpointError instanceof AgentSdkError\n && checkpointError.code === OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE\n ? checkpointError\n : new AgentSdkError(\n 'audit observation is unavailable before provider dispatch',\n OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE,\n { cause: checkpointError },\n )\n }\n } else capture(startEvent)\n\n let finalReport: AttemptUsageReport | undefined\n const end = (endInput: EndProviderAttemptInput): AttemptUsageReport => {\n if (finalReport !== undefined) return finalReport\n const endedAt = new Date().toISOString()\n const endedMonotonic = nowMonotonic()\n const validated = validateUsageCounters(endInput.reported, true)\n const coverage: UsageCoverage = endInput.dispatchState === 'not-sent'\n ? 'not-applicable'\n : validated.complete && endInput.usageFinal !== false ? 'complete'\n : Object.keys(validated.reported).length > 0 ? 'partial' : 'missing'\n const invalidError = validated.invalidFields.length > 0 || validated.overflow\n ? Object.freeze({\n type: 'UsageValidationError',\n message: validated.overflow\n ? 'provider attempt usage counters overflowed safe integer validation'\n : `provider attempt usage contained invalid fields: ${validated.invalidFields.join(', ')}`,\n code: validated.overflow\n ? OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW\n : OBSERVATION_ERROR_CODES.USAGE_INVALID,\n })\n : undefined\n const terminalError = endInput.error ?? invalidError\n const durationMs = Math.max(0, endedMonotonic - attemptStartedMonotonic)\n attemptSpan.end(endInput.status, endedAt, scope.monotonicMs())\n const terminalCorrelation = endInput.providerRequestId === undefined\n ? attemptSpan.correlation\n : deepFreeze({ ...attemptSpan.correlation, providerRequestId: endInput.providerRequestId })\n capture(deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.attempt',\n phase: 'end',\n occurredAt: endedAt,\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: terminalCorrelation,\n data: {\n status: endInput.status,\n durationMs,\n origin: attemptInput.origin,\n dispatchState: endInput.dispatchState,\n coverage,\n reported: { ...validated.reported },\n ...endInput.httpStatus === undefined ? {} : { httpStatus: endInput.httpStatus },\n ...endInput.providerRequestId === undefined ? {} : { providerRequestId: endInput.providerRequestId },\n ...terminalError === undefined ? {} : { error: { ...terminalError } },\n },\n }))\n finalReport = deepFreeze({\n attemptId,\n spanId: attemptSpan.correlation.spanId,\n attemptNumber,\n status: endInput.status,\n startedAt: attemptStartedAt,\n endedAt,\n durationMs,\n dispatchState: endInput.dispatchState,\n coverage,\n reported: validated.reported,\n origin: attemptInput.origin,\n ...endInput.httpStatus === undefined ? {} : { httpStatus: endInput.httpStatus },\n ...endInput.providerRequestId === undefined ? {} : { providerRequestId: endInput.providerRequestId },\n ...terminalError === undefined ? {} : { error: terminalError },\n })\n attempts.push(finalReport)\n openAttempts.delete(end)\n return finalReport\n }\n openAttempts.add(end)\n return Object.freeze({ attemptId, attemptNumber, traceparent: attemptSpan.traceparent, end })\n }\n const effectiveContext: ModelInvocationContext = Object.freeze({\n observation: port,\n resource: input.resource,\n correlation: span.correlation,\n terminalCheckpointOwner: input.context?.terminalCheckpointOwner ?? 'model-call',\n scope,\n ...(input.context?.logger === undefined ? {} : { logger: input.context.logger }),\n declareProviderAttemptAccounting: () => { providerAttemptAccountingDeclared = true },\n startProviderAttempt,\n recordProviderRetry,\n })\n capture(makeEvent('start', {\n provider: input.options.provider,\n model: input.options.model,\n operation: 'stream',\n }))\n\n let resolveReport: (report: ModelCallReport) => void = () => {}\n const report = new Promise<ModelCallReport>((resolvePromise) => { resolveReport = resolvePromise })\n let finalized = false\n let iterated = false\n let status: OperationStatus = 'unknown'\n let finishReason: string | undefined\n let error: SafeErrorRecord | undefined\n let usage: TokenUsage | undefined\n\n const finalize = async (): Promise<{ report: ModelCallReport; auditFailure: boolean }> => {\n if (finalized) return { report: await report, auditFailure: false }\n finalized = true\n const endedAt = new Date().toISOString()\n const endedMonotonic = nowMonotonic()\n if (status === 'unknown') {\n error ??= Object.freeze({\n type: 'OperationTerminalError',\n message: 'model call closed without a terminal finish reason',\n code: OBSERVATION_ERROR_CODES.OPERATION_TERMINAL_MISSING,\n })\n }\n for (const closeAttempt of [...openAttempts]) {\n closeAttempt({\n status: status === 'aborted' ? 'aborted' : 'unknown',\n dispatchState: input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown',\n ...(error === undefined ? {} : { error }),\n })\n }\n try { span.end(status, endedAt, scope.monotonicMs()) } catch (spanError) { tracker.lastFailure = safeErrorRecord(spanError) }\n\n const validated = usage === undefined ? undefined : validateUsageCounters(usage, true)\n const preDispatch = !input.routePresent || input.dispatchState() === 'not-sent'\n const coverage: UsageCoverage = attempts.length > 0 || providerAttemptAccountingDeclared\n ? classifyUsageCoverage(attempts)\n : validated === undefined\n ? preDispatch ? 'not-applicable' : 'missing'\n : validated.complete ? 'complete' : 'partial'\n if (validated && (validated.invalidFields.length > 0 || validated.overflow)) {\n error ??= Object.freeze({\n type: 'UsageValidationError',\n message: validated.overflow\n ? 'provider usage counters overflowed safe integer aggregation'\n : `provider usage contained invalid fields: ${validated.invalidFields.join(', ')}`,\n code: validated.overflow ? OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW : OBSERVATION_ERROR_CODES.USAGE_INVALID,\n })\n } else if (coverage === 'missing' && error === undefined) {\n error = Object.freeze({\n type: 'UsageMissingError',\n message: 'model call may have been dispatched but no provider usage was reported',\n code: OBSERVATION_ERROR_CODES.USAGE_MISSING,\n })\n }\n const durationMs = Math.max(0, endedMonotonic - startedMonotonic)\n const attemptUsage = attempts.length === 0\n ? undefined\n : addUsageCounters(attempts.map(attempt => attempt.reported))\n const accountingOverflow = attemptUsage?.overflow === true || validated?.overflow === true\n if (accountingOverflow) error ??= Object.freeze({\n type: 'UsageValidationError', message: 'provider usage counters overflowed safe integer aggregation',\n code: OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW,\n })\n const reported = attemptUsage?.counters ?? validated?.reported ?? {}\n const endEvent = makeEvent('end', {\n status,\n durationMs,\n ...finishReason === undefined ? {} : { finishReason },\n dispatchState: attempts.at(-1)?.dispatchState\n ?? (input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown'),\n coverage,\n reported: { ...reported },\n attemptCount: attempts.length,\n })\n let auditFailure = false\n const checkpointOwner = effectiveContext.terminalCheckpointOwner ?? 'model-call'\n if (checkpointOwner === 'model-call' && mode !== 'operational') {\n tracker.pending += 1\n try {\n const rawReceipt = port.checkpoint\n ? await port.checkpoint(endEvent)\n : Object.freeze({ eventId: endEvent.eventId, status: 'rejected' as const, durable: false, boundary: 'none' as const, reason: 'exporter-unavailable' as const })\n const receipt = validateCaptureReceipt(rawReceipt, endEvent.eventId)\n tracker.pending -= 1\n applyReceipt(tracker, receipt, true)\n if (receipt.status !== 'accepted' || !receipt.durable) {\n auditFailure = mode === 'audit'\n tracker.lastFailure = Object.freeze({\n type: 'ObservationCheckpointError',\n message: `terminal observation checkpoint was ${receipt.status}`,\n code: OBSERVATION_ERROR_CODES.CAPTURE_REJECTED,\n })\n }\n } catch (checkpointError) {\n tracker.pending -= 1\n tracker.rejected += 1\n tracker.lastFailure = safeErrorRecord(checkpointError)\n auditFailure = mode === 'audit'\n }\n } else capture(endEvent)\n\n const finalReport = deepFreeze<ModelCallReport>({\n runId,\n traceId: span.correlation.traceId,\n modelCallId,\n spanId: span.correlation.spanId,\n provider: input.options.provider,\n ...input.providerFamily === undefined ? {} : { providerFamily: input.providerFamily },\n ...input.providerPluginId === undefined ? {} : { providerPluginId: input.providerPluginId },\n model: input.options.model,\n status,\n startedAt,\n endedAt,\n durationMs,\n ...finishReason === undefined ? {} : { finishReason },\n dispatchState: attempts.at(-1)?.dispatchState\n ?? (input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown'),\n coverage,\n reported,\n attempts: [...attempts].sort((left, right) => left.attemptNumber - right.attemptNumber),\n possiblyBilledAttemptsWithoutUsage: attempts.length > 0\n ? possiblyBilledAttemptsWithoutUsage(attempts)\n : coverage === 'missing' || coverage === 'partial' ? 1 : 0,\n authoritative: (coverage === 'complete' || coverage === 'not-applicable') && !accountingOverflow,\n delivery: deliverySummary(port, mode, tracker),\n ...error === undefined ? {} : { error },\n })\n resolveReport(finalReport)\n return { report: finalReport, auditFailure }\n }\n\n const iterate = async function* (): AsyncGenerator<StreamChunk> {\n let iterator: AsyncIterator<StreamChunk> | undefined\n let sourceDone = false\n let thrown: unknown\n try {\n iterator = input.stream(effectiveContext)[Symbol.asyncIterator]()\n while (true) {\n const item = await iterator.next()\n if (item.done) {\n sourceDone = true\n break\n }\n const chunk = item.value\n if (chunk.type === 'usage') usage = chunk.usage\n if (chunk.type === 'finish') {\n finishReason = chunk.reason.kind\n status = chunk.reason.kind === 'aborted' ? 'aborted'\n : chunk.reason.kind === 'error' ? 'error' : 'success'\n error = safeFailureFromFinish(chunk, input.isRetryable)\n }\n yield chunk\n }\n } catch (streamError) {\n thrown = streamError\n status = input.options.signal?.aborted === true ? 'aborted' : 'error'\n error = safeErrorRecord(streamError)\n throw streamError\n } finally {\n if (!sourceDone) {\n if (thrown === undefined) status = 'aborted'\n const close = iterator?.return?.bind(iterator)\n if (close) try { await close() } catch (closeError) { error ??= safeErrorRecord(closeError) }\n }\n const terminal = await finalize()\n if (terminal.auditFailure) {\n throw new ModelCallObservationError('audit observation checkpoint failed after model-call finalization', terminal.report)\n }\n }\n }\n\n return Object.freeze({\n runId,\n modelCallId,\n report,\n [Symbol.asyncIterator](): AsyncIterator<StreamChunk> {\n if (iterated) {\n return (async function* () { throw new Error('a model call handle can only be iterated once') })()\n }\n iterated = true\n return iterate()\n },\n })\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"model-call-handle.js","names":[],"sources":["../../src/runtime/model-call-handle.ts"],"sourcesContent":["import type { GenerateOptions } from '../contract/generate-options.ts'\nimport { deepFreeze } from '../primitives/freeze.ts'\nimport type { JsonObject } from '../primitives/json.ts'\nimport type { StreamChunk, TokenUsage } from '../stream/chunk.ts'\nimport { createObservationRunScope, createOperationId, isSpanId, isTraceId, type CorrelationContext, type ObservationRunScope } from '../observation/context.ts'\nimport { safeErrorRecord, type ObservationEvent, type ObservationResource, type OperationStatus, type SafeErrorRecord } from '../observation/event.ts'\nimport { createCoreSpan, disabledDeliverySummary, NOOP_OBSERVATION_PORT, snapshotObservationSpan, validateCaptureReceipt, type CaptureReceipt, type DeliveryMode, type ObservationBoundary, type ObservationDeliverySummary, type ObservationPort, type ObservationSpan } from '../observation/port.ts'\nimport { AgentSdkError } from '../errors/agent-sdk-error.ts'\nimport { ModelCallObservationError, OBSERVATION_ERROR_CODES, type EndProviderAttemptInput, type ModelCallHandle, type ModelCallReport, type ModelInvocationContext, type ProviderAttemptHandle, type ProviderRetryScheduledInput, type StartProviderAttemptInput } from '../observation/report.ts'\nimport { addUsageCounters, classifyUsageCoverage, possiblyBilledAttemptsWithoutUsage, validateUsageCounters, type AttemptUsageReport, type UsageCoverage } from '../observation/usage.ts'\n\nconst scopes = new WeakMap<object, Map<string, ObservationRunScope>>()\n\nfunction nowMonotonic(): number {\n return globalThis.performance?.now() ?? Date.now()\n}\n\nfunction scopeFor(key: object, runId: string, supplied?: ObservationRunScope): ObservationRunScope {\n if (supplied !== undefined) return supplied\n let runs = scopes.get(key)\n if (!runs) {\n runs = new Map()\n scopes.set(key, runs)\n }\n let scope = runs.get(runId)\n if (!scope) {\n scope = createObservationRunScope()\n runs.set(runId, scope)\n }\n return scope\n}\n\n/**\n * Carry the failure's own message through to the report untouched.\n *\n * A provider's rejection often names the exact reason (an unsupported\n * `reasoning.effort` value, a missing field, a quota message) that the\n * generic classification code cannot express — an agent or its caller reading\n * `report.error.message` needs that, not a pointer back to the code. Content\n * redaction belongs to the observation exporters (`observability.content` /\n * `redactors`), never to what this report itself carries.\n */\nfunction safeFailureFromFinish(\n chunk: Extract<StreamChunk, { type: 'finish' }>,\n isRetryable?: (code: string) => boolean,\n): SafeErrorRecord | undefined {\n if (chunk.reason.kind !== 'error' && chunk.reason.kind !== 'aborted') return undefined\n const failure = chunk.reason.failure\n return Object.freeze({\n type: 'ModelError',\n message: failure.message,\n code: failure.code,\n ...isRetryable === undefined ? {} : { retryable: isRetryable(failure.code) },\n ...failure.status === undefined ? {} : { status: failure.status },\n })\n}\n\nfunction boundaryRank(boundary: ObservationBoundary): number {\n if (boundary === 'remote-acknowledged') return 2\n if (boundary === 'local-durable') return 1\n return 0\n}\n\ninterface DeliveryTracker {\n accepted: number\n rejected: number\n pending: number\n reached: ObservationBoundary\n lastFailure?: SafeErrorRecord\n}\n\nfunction applyReceipt(tracker: DeliveryTracker, receipt: CaptureReceipt, critical: boolean): void {\n if (!critical) return\n if (receipt.status === 'accepted') tracker.accepted += 1\n else tracker.rejected += 1\n if (receipt.status === 'accepted' && boundaryRank(receipt.boundary) > boundaryRank(tracker.reached)) tracker.reached = receipt.boundary\n}\n\nfunction deliverySummary(port: ObservationPort, mode: DeliveryMode, tracker: DeliveryTracker): ObservationDeliverySummary {\n if (port === NOOP_OBSERVATION_PORT) return disabledDeliverySummary()\n const requiredBoundary: ObservationBoundary = mode === 'operational'\n ? 'none'\n : boundaryRank(tracker.reached) > 0 ? tracker.reached : 'local-durable'\n return deepFreeze({\n mode,\n requiredBoundary,\n reachedBoundary: tracker.reached,\n complete: tracker.rejected === 0 && tracker.pending === 0\n && boundaryRank(tracker.reached) >= boundaryRank(requiredBoundary),\n acceptedCritical: tracker.accepted,\n rejectedCritical: tracker.rejected,\n pendingCritical: tracker.pending,\n ...tracker.lastFailure === undefined ? {} : { lastFailure: tracker.lastFailure },\n })\n}\n\nfunction validParent(value: Partial<CorrelationContext> | undefined): CorrelationContext | undefined {\n if (!value || !isTraceId(value.traceId) || !isSpanId(value.spanId)\n || typeof value.runId !== 'string' || value.runId.length === 0) return undefined\n return {\n traceId: value.traceId,\n spanId: value.spanId,\n parentSpanId: value.parentSpanId === null || isSpanId(value.parentSpanId) ? value.parentSpanId : null,\n runId: value.runId,\n ...value.conversationId === undefined ? {} : { conversationId: value.conversationId },\n ...value.turnId === undefined ? {} : { turnId: value.turnId },\n ...value.modelCallId === undefined ? {} : { modelCallId: value.modelCallId },\n ...value.attemptId === undefined ? {} : { attemptId: value.attemptId },\n ...value.toolCallId === undefined ? {} : { toolCallId: value.toolCallId },\n ...value.providerRequestId === undefined ? {} : { providerRequestId: value.providerRequestId },\n ...value.sessionId === undefined ? {} : { sessionId: value.sessionId },\n }\n}\n\nfunction openContainedSpan(port: ObservationPort, input: Parameters<ObservationPort['openSpan']>[0], tracker: DeliveryTracker): ObservationSpan {\n try {\n const span = snapshotObservationSpan(port.openSpan(input))\n if (span && span.correlation.runId === input.runId\n && span.correlation.modelCallId === input.correlation?.modelCallId) {\n let ended = false\n return Object.freeze({\n correlation: span.correlation,\n traceparent: span.traceparent,\n end(status: OperationStatus, endedAt: string, monotonicMs: number): void {\n if (ended) return\n ended = true\n try { span.end(status, endedAt, monotonicMs) } catch (error) { tracker.lastFailure = safeErrorRecord(error) }\n },\n })\n }\n tracker.lastFailure = Object.freeze({\n type: 'ObservationSpanError',\n message: 'observation backend returned an invalid or mismatched span identity',\n code: OBSERVATION_ERROR_CODES.OTEL_PROVIDER_UNCONFIGURED,\n })\n } catch (error) {\n tracker.lastFailure = safeErrorRecord(error)\n }\n return createCoreSpan(input)\n}\n\nexport interface CreateModelCallHandleOptions {\n readonly options: GenerateOptions\n readonly providerFamily?: string\n readonly providerPluginId?: string\n readonly isRetryable?: (code: string) => boolean\n readonly context?: ModelInvocationContext\n readonly defaultObservation?: ObservationPort\n readonly resource: ObservationResource\n readonly routePresent: boolean\n readonly dispatchState: () => 'not-sent' | 'unknown'\n readonly stream: (context: ModelInvocationContext) => AsyncIterable<StreamChunk>\n}\n\nexport function createModelCallHandle(input: CreateModelCallHandleOptions): ModelCallHandle {\n const contextKey = input.context ?? {}\n const supplied = input.context?.correlation\n const runId = typeof supplied?.runId === 'string' && supplied.runId.length > 0 ? supplied.runId : createOperationId()\n const modelCallId = typeof supplied?.modelCallId === 'string' && supplied.modelCallId.length > 0 ? supplied.modelCallId : createOperationId()\n const scope = scopeFor(contextKey, runId, input.context?.scope)\n const startedAt = new Date().toISOString()\n const startedMonotonic = nowMonotonic()\n const port = input.context?.observation ?? input.defaultObservation ?? NOOP_OBSERVATION_PORT\n const tracker: DeliveryTracker = { accepted: 0, rejected: 0, pending: 0, reached: 'none' }\n let mode: DeliveryMode = 'operational'\n try {\n const configuredMode = port.mode\n if (configuredMode !== 'operational' && configuredMode !== 'reliable' && configuredMode !== 'audit') {\n throw new TypeError('observation delivery mode is invalid')\n }\n mode = configuredMode\n } catch (modeError) {\n tracker.lastFailure = safeErrorRecord(modeError)\n }\n const parent = validParent(supplied)\n const span = openContainedSpan(port, {\n name: 'sdk.model.call',\n runId,\n ...(parent === undefined ? {} : { parent }),\n correlation: {\n modelCallId,\n ...supplied?.conversationId === undefined ? {} : { conversationId: supplied.conversationId },\n ...supplied?.turnId === undefined ? {} : { turnId: supplied.turnId },\n ...supplied?.sessionId === undefined ? {} : { sessionId: supplied.sessionId },\n },\n startedAt,\n monotonicMs: scope.monotonicMs(),\n }, tracker)\n const makeEvent = (phase: 'start' | 'end', data: JsonObject): ObservationEvent<'sdk.model.call'> => deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.model.call',\n phase,\n occurredAt: new Date().toISOString(),\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: span.correlation,\n data,\n })\n\n const capture = (event: ObservationEvent): void => {\n try {\n const receipt = validateCaptureReceipt(port.capture(event), event.eventId)\n applyReceipt(tracker, receipt, event.priority === 'critical')\n } catch (error) {\n tracker.rejected += event.priority === 'critical' ? 1 : 0\n tracker.lastFailure = safeErrorRecord(error)\n }\n }\n\n const attempts: AttemptUsageReport[] = []\n const openAttempts = new Set<(input: EndProviderAttemptInput) => AttemptUsageReport>()\n let nextAttemptNumber = 1\n let providerAttemptAccountingDeclared = false\n\n function recordProviderRetry(retry: ProviderRetryScheduledInput): void {\n capture(deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.retry.scheduled',\n phase: 'point',\n occurredAt: new Date().toISOString(),\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: span.correlation,\n data: {\n nextAttemptNumber: retry.nextAttemptNumber,\n delayMs: retry.delayMs,\n failureCode: retry.failureCode,\n },\n }))\n }\n\n async function startProviderAttempt(\n attemptInput: StartProviderAttemptInput,\n signal?: AbortSignal,\n ): Promise<ProviderAttemptHandle> {\n const attemptNumber = nextAttemptNumber++\n const attemptId = createOperationId()\n const attemptStartedAt = new Date().toISOString()\n const attemptStartedMonotonic = nowMonotonic()\n const attemptSpan = openContainedSpan(port, {\n name: 'sdk.provider.attempt',\n runId,\n parent: span.correlation,\n correlation: { modelCallId, attemptId },\n startedAt: attemptStartedAt,\n monotonicMs: scope.monotonicMs(),\n }, tracker)\n const startEvent: ObservationEvent<'sdk.provider.attempt'> = deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.attempt',\n phase: 'start',\n occurredAt: attemptStartedAt,\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: attemptSpan.correlation,\n data: {\n provider: attemptInput.provider,\n model: attemptInput.model,\n attemptNumber,\n method: attemptInput.method,\n origin: attemptInput.origin,\n dispatchState: 'not-sent',\n },\n })\n\n if (mode === 'audit') {\n tracker.pending += 1\n try {\n const rawReceipt = port.checkpoint\n ? await port.checkpoint(startEvent, signal)\n : Object.freeze({\n eventId: startEvent.eventId,\n status: 'rejected' as const,\n durable: false,\n boundary: 'none' as const,\n reason: 'exporter-unavailable' as const,\n })\n const receipt = validateCaptureReceipt(rawReceipt, startEvent.eventId)\n tracker.pending -= 1\n applyReceipt(tracker, receipt, true)\n if (receipt.status !== 'accepted' || !receipt.durable) {\n if (receipt.status === 'accepted') tracker.rejected += 1\n tracker.lastFailure = Object.freeze({\n type: 'ObservationCheckpointError',\n message: `provider-attempt audit checkpoint was ${receipt.status}`,\n code: OBSERVATION_ERROR_CODES.CAPTURE_REJECTED,\n })\n attemptSpan.end('rejected', new Date().toISOString(), scope.monotonicMs())\n throw new AgentSdkError(\n 'audit observation is unavailable before provider dispatch',\n OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE,\n )\n }\n } catch (checkpointError) {\n if (tracker.pending > 0) tracker.pending -= 1\n if (!(checkpointError instanceof AgentSdkError\n && checkpointError.code === OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE)) {\n tracker.rejected += 1\n tracker.lastFailure = safeErrorRecord(checkpointError)\n attemptSpan.end('rejected', new Date().toISOString(), scope.monotonicMs())\n }\n throw checkpointError instanceof AgentSdkError\n && checkpointError.code === OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE\n ? checkpointError\n : new AgentSdkError(\n 'audit observation is unavailable before provider dispatch',\n OBSERVATION_ERROR_CODES.AUDIT_UNAVAILABLE,\n { cause: checkpointError },\n )\n }\n } else capture(startEvent)\n\n let finalReport: AttemptUsageReport | undefined\n const end = (endInput: EndProviderAttemptInput): AttemptUsageReport => {\n if (finalReport !== undefined) return finalReport\n const endedAt = new Date().toISOString()\n const endedMonotonic = nowMonotonic()\n const validated = validateUsageCounters(endInput.reported, true)\n const coverage: UsageCoverage = endInput.dispatchState === 'not-sent'\n ? 'not-applicable'\n : validated.complete && endInput.usageFinal !== false ? 'complete'\n : Object.keys(validated.reported).length > 0 ? 'partial' : 'missing'\n const invalidError = validated.invalidFields.length > 0 || validated.overflow\n ? Object.freeze({\n type: 'UsageValidationError',\n message: validated.overflow\n ? 'provider attempt usage counters overflowed safe integer validation'\n : `provider attempt usage contained invalid fields: ${validated.invalidFields.join(', ')}`,\n code: validated.overflow\n ? OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW\n : OBSERVATION_ERROR_CODES.USAGE_INVALID,\n })\n : undefined\n const terminalError = endInput.error ?? invalidError\n const durationMs = Math.max(0, endedMonotonic - attemptStartedMonotonic)\n attemptSpan.end(endInput.status, endedAt, scope.monotonicMs())\n const terminalCorrelation = endInput.providerRequestId === undefined\n ? attemptSpan.correlation\n : deepFreeze({ ...attemptSpan.correlation, providerRequestId: endInput.providerRequestId })\n capture(deepFreeze({\n schemaVersion: 1,\n eventId: createOperationId(),\n sequence: scope.nextSequence(),\n name: 'sdk.provider.attempt',\n phase: 'end',\n occurredAt: endedAt,\n monotonicMs: scope.monotonicMs(),\n priority: 'critical',\n resource: input.resource,\n correlation: terminalCorrelation,\n data: {\n status: endInput.status,\n durationMs,\n origin: attemptInput.origin,\n dispatchState: endInput.dispatchState,\n coverage,\n reported: { ...validated.reported },\n ...endInput.httpStatus === undefined ? {} : { httpStatus: endInput.httpStatus },\n ...endInput.providerRequestId === undefined ? {} : { providerRequestId: endInput.providerRequestId },\n ...terminalError === undefined ? {} : { error: { ...terminalError } },\n },\n }))\n finalReport = deepFreeze({\n attemptId,\n spanId: attemptSpan.correlation.spanId,\n attemptNumber,\n status: endInput.status,\n startedAt: attemptStartedAt,\n endedAt,\n durationMs,\n dispatchState: endInput.dispatchState,\n coverage,\n reported: validated.reported,\n origin: attemptInput.origin,\n ...endInput.httpStatus === undefined ? {} : { httpStatus: endInput.httpStatus },\n ...endInput.providerRequestId === undefined ? {} : { providerRequestId: endInput.providerRequestId },\n ...terminalError === undefined ? {} : { error: terminalError },\n })\n attempts.push(finalReport)\n openAttempts.delete(end)\n return finalReport\n }\n openAttempts.add(end)\n return Object.freeze({ attemptId, attemptNumber, traceparent: attemptSpan.traceparent, end })\n }\n const effectiveContext: ModelInvocationContext = Object.freeze({\n observation: port,\n resource: input.resource,\n correlation: span.correlation,\n terminalCheckpointOwner: input.context?.terminalCheckpointOwner ?? 'model-call',\n scope,\n ...(input.context?.logger === undefined ? {} : { logger: input.context.logger }),\n ...(input.context?.agentId === undefined ? {} : { agentId: input.context.agentId }),\n ...(input.context?.providerOptions === undefined ? {} : { providerOptions: input.context.providerOptions }),\n declareProviderAttemptAccounting: () => { providerAttemptAccountingDeclared = true },\n startProviderAttempt,\n recordProviderRetry,\n })\n capture(makeEvent('start', {\n provider: input.options.provider,\n model: input.options.model,\n operation: 'stream',\n }))\n\n let resolveReport: (report: ModelCallReport) => void = () => {}\n const report = new Promise<ModelCallReport>((resolvePromise) => { resolveReport = resolvePromise })\n let finalized = false\n let iterated = false\n let status: OperationStatus = 'unknown'\n let finishReason: string | undefined\n let error: SafeErrorRecord | undefined\n let usage: TokenUsage | undefined\n\n const finalize = async (): Promise<{ report: ModelCallReport; auditFailure: boolean }> => {\n if (finalized) return { report: await report, auditFailure: false }\n finalized = true\n const endedAt = new Date().toISOString()\n const endedMonotonic = nowMonotonic()\n if (status === 'unknown') {\n error ??= Object.freeze({\n type: 'OperationTerminalError',\n message: 'model call closed without a terminal finish reason',\n code: OBSERVATION_ERROR_CODES.OPERATION_TERMINAL_MISSING,\n })\n }\n for (const closeAttempt of [...openAttempts]) {\n closeAttempt({\n status: status === 'aborted' ? 'aborted' : 'unknown',\n dispatchState: input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown',\n ...(error === undefined ? {} : { error }),\n })\n }\n try { span.end(status, endedAt, scope.monotonicMs()) } catch (spanError) { tracker.lastFailure = safeErrorRecord(spanError) }\n\n const validated = usage === undefined ? undefined : validateUsageCounters(usage, true)\n const preDispatch = !input.routePresent || input.dispatchState() === 'not-sent'\n const coverage: UsageCoverage = attempts.length > 0 || providerAttemptAccountingDeclared\n ? classifyUsageCoverage(attempts)\n : validated === undefined\n ? preDispatch ? 'not-applicable' : 'missing'\n : validated.complete ? 'complete' : 'partial'\n if (validated && (validated.invalidFields.length > 0 || validated.overflow)) {\n error ??= Object.freeze({\n type: 'UsageValidationError',\n message: validated.overflow\n ? 'provider usage counters overflowed safe integer aggregation'\n : `provider usage contained invalid fields: ${validated.invalidFields.join(', ')}`,\n code: validated.overflow ? OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW : OBSERVATION_ERROR_CODES.USAGE_INVALID,\n })\n } else if (coverage === 'missing' && error === undefined) {\n error = Object.freeze({\n type: 'UsageMissingError',\n message: 'model call may have been dispatched but no provider usage was reported',\n code: OBSERVATION_ERROR_CODES.USAGE_MISSING,\n })\n }\n const durationMs = Math.max(0, endedMonotonic - startedMonotonic)\n const attemptUsage = attempts.length === 0\n ? undefined\n : addUsageCounters(attempts.map(attempt => attempt.reported))\n const accountingOverflow = attemptUsage?.overflow === true || validated?.overflow === true\n if (accountingOverflow) error ??= Object.freeze({\n type: 'UsageValidationError', message: 'provider usage counters overflowed safe integer aggregation',\n code: OBSERVATION_ERROR_CODES.USAGE_COUNTER_OVERFLOW,\n })\n const reported = attemptUsage?.counters ?? validated?.reported ?? {}\n const endEvent = makeEvent('end', {\n status,\n durationMs,\n ...finishReason === undefined ? {} : { finishReason },\n dispatchState: attempts.at(-1)?.dispatchState\n ?? (input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown'),\n coverage,\n reported: { ...reported },\n attemptCount: attempts.length,\n })\n let auditFailure = false\n const checkpointOwner = effectiveContext.terminalCheckpointOwner ?? 'model-call'\n if (checkpointOwner === 'model-call' && mode !== 'operational') {\n tracker.pending += 1\n try {\n const rawReceipt = port.checkpoint\n ? await port.checkpoint(endEvent)\n : Object.freeze({ eventId: endEvent.eventId, status: 'rejected' as const, durable: false, boundary: 'none' as const, reason: 'exporter-unavailable' as const })\n const receipt = validateCaptureReceipt(rawReceipt, endEvent.eventId)\n tracker.pending -= 1\n applyReceipt(tracker, receipt, true)\n if (receipt.status !== 'accepted' || !receipt.durable) {\n auditFailure = mode === 'audit'\n tracker.lastFailure = Object.freeze({\n type: 'ObservationCheckpointError',\n message: `terminal observation checkpoint was ${receipt.status}`,\n code: OBSERVATION_ERROR_CODES.CAPTURE_REJECTED,\n })\n }\n } catch (checkpointError) {\n tracker.pending -= 1\n tracker.rejected += 1\n tracker.lastFailure = safeErrorRecord(checkpointError)\n auditFailure = mode === 'audit'\n }\n } else capture(endEvent)\n\n const finalReport = deepFreeze<ModelCallReport>({\n runId,\n traceId: span.correlation.traceId,\n modelCallId,\n spanId: span.correlation.spanId,\n provider: input.options.provider,\n ...input.providerFamily === undefined ? {} : { providerFamily: input.providerFamily },\n ...input.providerPluginId === undefined ? {} : { providerPluginId: input.providerPluginId },\n model: input.options.model,\n status,\n startedAt,\n endedAt,\n durationMs,\n ...finishReason === undefined ? {} : { finishReason },\n dispatchState: attempts.at(-1)?.dispatchState\n ?? (input.dispatchState() === 'not-sent' ? 'not-sent' : 'unknown'),\n coverage,\n reported,\n attempts: [...attempts].sort((left, right) => left.attemptNumber - right.attemptNumber),\n possiblyBilledAttemptsWithoutUsage: attempts.length > 0\n ? possiblyBilledAttemptsWithoutUsage(attempts)\n : coverage === 'missing' || coverage === 'partial' ? 1 : 0,\n authoritative: (coverage === 'complete' || coverage === 'not-applicable') && !accountingOverflow,\n delivery: deliverySummary(port, mode, tracker),\n ...error === undefined ? {} : { error },\n })\n resolveReport(finalReport)\n return { report: finalReport, auditFailure }\n }\n\n const iterate = async function* (): AsyncGenerator<StreamChunk> {\n let iterator: AsyncIterator<StreamChunk> | undefined\n let sourceDone = false\n let thrown: unknown\n try {\n iterator = input.stream(effectiveContext)[Symbol.asyncIterator]()\n while (true) {\n const item = await iterator.next()\n if (item.done) {\n sourceDone = true\n break\n }\n const chunk = item.value\n if (chunk.type === 'usage') usage = chunk.usage\n if (chunk.type === 'finish') {\n finishReason = chunk.reason.kind\n status = chunk.reason.kind === 'aborted' ? 'aborted'\n : chunk.reason.kind === 'error' ? 'error' : 'success'\n error = safeFailureFromFinish(chunk, input.isRetryable)\n }\n yield chunk\n }\n } catch (streamError) {\n thrown = streamError\n status = input.options.signal?.aborted === true ? 'aborted' : 'error'\n error = safeErrorRecord(streamError)\n throw streamError\n } finally {\n if (!sourceDone) {\n if (thrown === undefined) status = 'aborted'\n const close = iterator?.return?.bind(iterator)\n if (close) try { await close() } catch (closeError) { error ??= safeErrorRecord(closeError) }\n }\n const terminal = await finalize()\n if (terminal.auditFailure) {\n throw new ModelCallObservationError('audit observation checkpoint failed after model-call finalization', terminal.report)\n }\n }\n }\n\n return Object.freeze({\n runId,\n modelCallId,\n report,\n [Symbol.asyncIterator](): AsyncIterator<StreamChunk> {\n if (iterated) {\n return (async function* () { throw new Error('a model call handle can only be iterated once') })()\n }\n iterated = true\n return iterate()\n },\n })\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{deepFreeze as e}from"../primitives/freeze.js";import{ModelError as t,REGISTRY_ERROR_CODES as n}from"../errors/model-error.js";import{freezeMessage as r}from"../message/message.js";function i(e,r,i,a){if(!Array.isArray(r))throw new t(`route "${e}" returned a catalog that is not an array`,n.INVALID_CATALOG);if(r.length>i||f(r,n.INVALID_CATALOG)>a)throw new t(`route "${e}" catalog exceeds the configured registry limit`,n.INVALID_CATALOG);let o=new Set;return r.map(r=>{if(r.provider!==e||typeof r.id!=`string`||r.id.length===0||typeof r.name!=`string`||r.name.length===0)throw new t(`route "${e}" advertised a model entry with invalid identity`,n.INVALID_CATALOG);if(o.has(r.id))throw new t(`route "${e}" advertised model "${r.id}" more than once`,n.INVALID_CATALOG);return o.add(r.id),structuredClone(r)})}function a(r,a,o,s){if(typeof a!=`object`||!a||a.provider?.id!==r||typeof a.provider.name!=`string`||a.provider.name.length===0||![`static`,`fresh`,`empty`,`stale`,`unavailable`].includes(a.state)||typeof a.revision!=`string`||a.revision.length===0||typeof a.observedAt!=`string`||!Number.isFinite(Date.parse(a.observedAt)))throw new t(`route "${r}" returned an invalid catalog snapshot`,n.INVALID_CATALOG);let c=i(r,a.models,o,s);return e({...structuredClone(a),provider:{...a.provider},models:c})}function o(r,i,a,o){if(a.provider!==r||a.id!==i||typeof a.name!=`string`||a.name.length===0)throw l(r,i,`mismatched identity`);if(a.context!==void 0&&(!Number.isSafeInteger(a.context.contextWindow)||a.context.contextWindow<=0))throw l(r,i,`a non-positive context window`);if(a.defaultMaxTokens!==void 0&&(!Number.isSafeInteger(a.defaultMaxTokens)||a.defaultMaxTokens<=0))throw l(r,i,`a non-positive defaultMaxTokens`);for(let e of[a.context?.maxContextWindow,a.context?.defaultContextWindow,a.context?.standardPriceInputTokens])if(e!==void 0&&(!Number.isSafeInteger(e)||e<=0))throw l(r,i,`invalid context policy`);if(a.context?.maxContextWindow!==void 0&&(a.context.contextWindow>a.context.maxContextWindow||(a.context.defaultContextWindow??0)>a.context.maxContextWindow))throw l(r,i,`contextWindow above maxContextWindow`);if(a.maxOutputTokens!==void 0&&(!Number.isSafeInteger(a.maxOutputTokens)||a.maxOutputTokens<=0))throw l(r,i,`a non-positive maxOutputTokens`);if(a.defaultMaxTokens!==void 0&&a.maxOutputTokens!==void 0&&a.defaultMaxTokens>a.maxOutputTokens)throw l(r,i,`defaultMaxTokens above maxOutputTokens`);if(a.context!==void 0&&a.defaultMaxTokens!==void 0&&a.defaultMaxTokens>=a.context.contextWindow||a.context!==void 0&&a.maxOutputTokens!==void 0&&a.maxOutputTokens>=(a.context.maxContextWindow??a.context.contextWindow))throw l(r,i,`no input headroom`);s(r,i,a),c(r,i,a);let u=e(structuredClone({...a,...a.inputModalities===void 0?{}:{inputModalities:[...a.inputModalities]},...a.outputModalities===void 0?{}:{outputModalities:[...a.outputModalities]},...a.nativeTools===void 0?{}:{nativeTools:[...a.nativeTools]}}));if(f(u,n.INVALID_MODEL_INFO)>o)throw new t(`route "${r}" model metadata exceeds the configured registry limit`,n.INVALID_MODEL_INFO);return u}function s(e,t,n){if(n.reasoning===void 0)return;let r=n.reasoning.efforts.map(e=>e.id);if(r.length===0||new Set(r).size!==r.length||n.reasoning.efforts.some(e=>typeof e.id!=`string`||e.id.length===0||typeof e.name!=`string`||e.name.length===0))throw l(e,t,`empty or duplicated reasoning efforts`);if(n.reasoning.defaultEffort!==void 0&&!r.includes(n.reasoning.defaultEffort))throw l(e,t,`a default reasoning effort it does not offer`)}function c(e,t,n){for(let[r,i]of[[`input modalities`,n.inputModalities],[`output modalities`,n.outputModalities],[`native tools`,n.nativeTools]])if(i!==void 0&&(new Set(i).size!==i.length||i.some(e=>typeof e!=`string`||e.length===0)))throw l(e,t,`invalid ${r}`)}function l(e,r,i){return new t(`route "${e}" resolved model "${r}" with ${i}`,n.INVALID_MODEL_INFO)}function u(e,r){let i=e.reasoningEffort??r.reasoning?.defaultEffort;if(e.reasoningEffort!==void 0&&r.reasoning?.efforts.some(t=>t.id===e.reasoningEffort)!==!0)throw new t(`model "${r.id}" on route "${r.provider}" does not offer reasoning effort "${e.reasoningEffort}"`,n.UNSUPPORTED_REASONING_EFFORT);let a=e.maxTokens??r.defaultMaxTokens;if(a!==void 0&&r.maxOutputTokens!==void 0&&a>r.maxOutputTokens)throw new t(`model "${r.id}" on route "${r.provider}" supports at most ${r.maxOutputTokens} output tokens, received ${a}`,n.OUTPUT_TOKEN_LIMIT_EXCEEDED);if(a!==void 0&&r.context!==void 0&&a>=r.context.contextWindow)throw new t(`model "${r.id}" on route "${r.provider}" cannot reserve ${a} output tokens inside its ${r.context.contextWindow}-token combined context window`,n.OUTPUT_TOKEN_LIMIT_EXCEEDED);return{config:{provider:e.provider,model:e.model,...i===void 0?{}:{reasoningEffort:i},...e.temperature===void 0?{}:{temperature:e.temperature},...e.topP===void 0?{}:{topP:e.topP},...a===void 0?{}:{maxTokens:a},...e.stop===void 0?{}:{stop:[...e.stop]}},context:r.context}}function d(e,t,n){let i=e.messages.map(e=>{let i=e.source;return e.role!==`assistant`||i.kind!==`model`||i.replayState===void 0||n(i.provider)===t?e:r({...e,source:{kind:`model`,provider:i.provider,model:i.model}})});return i.every((t,n)=>t===e.messages[n])?e:{...e,messages:i}}function f(e,n){let r;try{r=JSON.stringify(e)}catch(e){throw new t(`adapter model metadata must be JSON-serializable`,n,{cause:e})}if(r===void 0)throw new t(`adapter model metadata must be JSON-serializable`,n);return new TextEncoder().encode(r).byteLength}export{o as normalizeResolvedModelInfo,d as projectReplayForAdapter,u as resolveCallWithModelInfo,i as validateCatalogModels,a as validateModelCatalogSnapshot};
1
+ import{deepFreeze as e}from"../primitives/freeze.js";import{ModelError as t,REGISTRY_ERROR_CODES as n}from"../errors/model-error.js";import{freezeMessage as r}from"../message/message.js";const i=2e5,a=Object.freeze([`text`,`image`,`document`]);function o(e,r,i,a){if(!Array.isArray(r))throw new t(`route "${e}" returned a catalog that is not an array`,n.INVALID_CATALOG);if(r.length>i||m(r,n.INVALID_CATALOG)>a)throw new t(`route "${e}" catalog exceeds the configured registry limit`,n.INVALID_CATALOG);let o=new Set;return r.map(r=>{if(r.provider!==e||typeof r.id!=`string`||r.id.length===0||typeof r.name!=`string`||r.name.length===0)throw new t(`route "${e}" advertised a model entry with invalid identity`,n.INVALID_CATALOG);if(o.has(r.id))throw new t(`route "${e}" advertised model "${r.id}" more than once`,n.INVALID_CATALOG);return o.add(r.id),structuredClone(r)})}function s(r,i,a,s){if(typeof i!=`object`||!i||i.provider?.id!==r||typeof i.provider.name!=`string`||i.provider.name.length===0||![`static`,`fresh`,`empty`,`stale`,`unavailable`].includes(i.state)||typeof i.revision!=`string`||i.revision.length===0||typeof i.observedAt!=`string`||!Number.isFinite(Date.parse(i.observedAt)))throw new t(`route "${r}" returned an invalid catalog snapshot`,n.INVALID_CATALOG);let c=o(r,i.models,a,s);return e({...structuredClone(i),provider:{...i.provider},models:c})}function c(r,i,o,s,c={}){if(o.provider!==r||o.id!==i||typeof o.name!=`string`||o.name.length===0)throw d(r,i,`mismatched identity`);if(o.context!==void 0&&(!Number.isSafeInteger(o.context.contextWindow)||o.context.contextWindow<=0))throw d(r,i,`a non-positive context window`);if(o.defaultMaxTokens!==void 0&&(!Number.isSafeInteger(o.defaultMaxTokens)||o.defaultMaxTokens<=0))throw d(r,i,`a non-positive defaultMaxTokens`);for(let e of[o.context?.maxContextWindow,o.context?.defaultContextWindow,o.context?.standardPriceInputTokens])if(e!==void 0&&(!Number.isSafeInteger(e)||e<=0))throw d(r,i,`invalid context policy`);if(o.context?.maxContextWindow!==void 0&&(o.context.contextWindow>o.context.maxContextWindow||(o.context.defaultContextWindow??0)>o.context.maxContextWindow))throw d(r,i,`contextWindow above maxContextWindow`);if(o.maxOutputTokens!==void 0&&(!Number.isSafeInteger(o.maxOutputTokens)||o.maxOutputTokens<=0))throw d(r,i,`a non-positive maxOutputTokens`);if(o.defaultMaxTokens!==void 0&&o.maxOutputTokens!==void 0&&o.defaultMaxTokens>o.maxOutputTokens)throw d(r,i,`defaultMaxTokens above maxOutputTokens`);if(o.context!==void 0&&o.defaultMaxTokens!==void 0&&o.defaultMaxTokens>=o.context.contextWindow||o.context!==void 0&&o.maxOutputTokens!==void 0&&o.maxOutputTokens>=(o.context.maxContextWindow??o.context.contextWindow))throw d(r,i,`no input headroom`);l(r,i,o),u(r,i,o);let f=o.context?.contextWindow??c.contextWindow??2e5,p=o.inputModalities??c.inputModalities??a,h=e(structuredClone({...o,context:{...o.context,contextWindow:f},inputModalities:[...p],...o.outputModalities===void 0?{}:{outputModalities:[...o.outputModalities]},...o.nativeTools===void 0?{}:{nativeTools:[...o.nativeTools]}}));if(m(h,n.INVALID_MODEL_INFO)>s)throw new t(`route "${r}" model metadata exceeds the configured registry limit`,n.INVALID_MODEL_INFO);return h}function l(e,t,n){if(n.reasoning===void 0)return;let r=n.reasoning.efforts.map(e=>e.id);if(r.length===0||new Set(r).size!==r.length||n.reasoning.efforts.some(e=>typeof e.id!=`string`||e.id.length===0||typeof e.name!=`string`||e.name.length===0))throw d(e,t,`empty or duplicated reasoning efforts`)}function u(e,t,n){for(let[r,i]of[[`input modalities`,n.inputModalities],[`output modalities`,n.outputModalities],[`native tools`,n.nativeTools]])if(i!==void 0&&(new Set(i).size!==i.length||i.some(e=>typeof e!=`string`||e.length===0)))throw d(e,t,`invalid ${r}`)}function d(e,r,i){return new t(`route "${e}" resolved model "${r}" with ${i}`,n.INVALID_MODEL_INFO)}function f(e,r,i={}){let a=e.reasoningEffort,o=e.contextWindow===void 0||r.context===void 0?r.context:{...r.context,contextWindow:e.contextWindow};if(o!==void 0&&o.maxContextWindow!==void 0&&o.contextWindow>o.maxContextWindow)throw new t(`model "${r.id}" on route "${r.provider}" was asked for a ${o.contextWindow}-token context window, above its ${o.maxContextWindow}-token technical ceiling`,n.INVALID_MODEL_INFO);let s=e.inputModalities??r.inputModalities,c=e.maxTokens??r.defaultMaxTokens??i.maxTokens;if(c!==void 0&&r.maxOutputTokens!==void 0&&c>r.maxOutputTokens)throw new t(`model "${r.id}" on route "${r.provider}" supports at most ${r.maxOutputTokens} output tokens, received ${c}`,n.OUTPUT_TOKEN_LIMIT_EXCEEDED);if(c!==void 0&&o!==void 0&&c>=o.contextWindow)throw new t(`model "${r.id}" on route "${r.provider}" cannot reserve ${c} output tokens inside its ${o.contextWindow}-token combined context window`,n.OUTPUT_TOKEN_LIMIT_EXCEEDED);return{config:{provider:e.provider,model:e.model,...a===void 0?{}:{reasoningEffort:a},...e.temperature===void 0?{}:{temperature:e.temperature},...e.topP===void 0?{}:{topP:e.topP},...c===void 0?{}:{maxTokens:c},...e.stop===void 0?{}:{stop:[...e.stop]},...e.contextWindow===void 0?{}:{contextWindow:e.contextWindow},...e.inputModalities===void 0?{}:{inputModalities:[...e.inputModalities]}},context:o,inputModalities:s}}function p(e,t,n){let i=e.messages.map(e=>{let i=e.source;return e.role!==`assistant`||i.kind!==`model`||i.replayState===void 0||n(i.provider)===t?e:r({...e,source:{kind:`model`,provider:i.provider,model:i.model}})});return i.every((t,n)=>t===e.messages[n])?e:{...e,messages:i}}function m(e,n){let r;try{r=JSON.stringify(e)}catch(e){throw new t(`adapter model metadata must be JSON-serializable`,n,{cause:e})}if(r===void 0)throw new t(`adapter model metadata must be JSON-serializable`,n);return new TextEncoder().encode(r).byteLength}export{i as DEFAULT_CONTEXT_WINDOW,a as DEFAULT_INPUT_MODALITIES,c as normalizeResolvedModelInfo,p as projectReplayForAdapter,f as resolveCallWithModelInfo,o as validateCatalogModels,s as validateModelCatalogSnapshot};
2
2
  //# sourceMappingURL=model-metadata.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-metadata.js","names":[],"sources":["../../src/runtime/model-metadata.ts"],"sourcesContent":["import type { ModelAdapter } from '../contract/adapter.ts'\nimport type { CallConfig } from '../contract/call-config.ts'\nimport type { GenerateOptions } from '../contract/generate-options.ts'\nimport type {\n ModelCatalogSnapshot,\n ModelContext,\n ModelInfo,\n ResolvedModelInfo,\n} from '../contract/model-info.ts'\nimport { ModelError, REGISTRY_ERROR_CODES } from '../errors/model-error.ts'\nimport { freezeMessage, type Message } from '../message/message.ts'\nimport { deepFreeze } from '../primitives/freeze.ts'\n\nexport function validateCatalogModels(\n provider: string,\n models: readonly ModelInfo[],\n maxModels: number,\n maxBytes: number,\n): ModelInfo[] {\n if (!Array.isArray(models)) {\n throw new ModelError(\n `route \"${provider}\" returned a catalog that is not an array`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n if (models.length > maxModels\n || serializedBytes(models, REGISTRY_ERROR_CODES.INVALID_CATALOG) > maxBytes) {\n throw new ModelError(\n `route \"${provider}\" catalog exceeds the configured registry limit`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n const seen = new Set<string>()\n return models.map((model) => {\n if (model.provider !== provider || typeof model.id !== 'string' || model.id.length === 0\n || typeof model.name !== 'string' || model.name.length === 0) {\n throw new ModelError(\n `route \"${provider}\" advertised a model entry with invalid identity`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n if (seen.has(model.id)) {\n throw new ModelError(\n `route \"${provider}\" advertised model \"${model.id}\" more than once`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n seen.add(model.id)\n return structuredClone(model)\n })\n}\n\nexport function validateModelCatalogSnapshot(\n provider: string,\n snapshot: ModelCatalogSnapshot,\n maxModels: number,\n maxBytes: number,\n): ModelCatalogSnapshot {\n if (typeof snapshot !== 'object' || snapshot === null\n || snapshot.provider?.id !== provider || typeof snapshot.provider.name !== 'string'\n || snapshot.provider.name.length === 0\n || !['static', 'fresh', 'empty', 'stale', 'unavailable'].includes(snapshot.state)\n || typeof snapshot.revision !== 'string' || snapshot.revision.length === 0\n || typeof snapshot.observedAt !== 'string' || !Number.isFinite(Date.parse(snapshot.observedAt))) {\n throw new ModelError(\n `route \"${provider}\" returned an invalid catalog snapshot`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n const models = validateCatalogModels(provider, snapshot.models, maxModels, maxBytes)\n return deepFreeze({ ...structuredClone(snapshot), provider: { ...snapshot.provider }, models })\n}\n\nexport function normalizeResolvedModelInfo(\n provider: string,\n model: string,\n info: ResolvedModelInfo,\n maxBytes: number,\n): ResolvedModelInfo {\n if (info.provider !== provider || info.id !== model\n || typeof info.name !== 'string' || info.name.length === 0) {\n throw invalidModel(provider, model, 'mismatched identity')\n }\n if (info.context !== undefined\n && (!Number.isSafeInteger(info.context.contextWindow) || info.context.contextWindow <= 0)) {\n throw invalidModel(provider, model, 'a non-positive context window')\n }\n if (info.defaultMaxTokens !== undefined\n && (!Number.isSafeInteger(info.defaultMaxTokens) || info.defaultMaxTokens <= 0)) {\n throw invalidModel(provider, model, 'a non-positive defaultMaxTokens')\n }\n for (const value of [info.context?.maxContextWindow, info.context?.defaultContextWindow, info.context?.standardPriceInputTokens]) {\n if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {\n throw invalidModel(provider, model, 'invalid context policy')\n }\n }\n if (info.context?.maxContextWindow !== undefined && (\n info.context.contextWindow > info.context.maxContextWindow\n || (info.context.defaultContextWindow ?? 0) > info.context.maxContextWindow\n )) throw invalidModel(provider, model, 'contextWindow above maxContextWindow')\n if (info.maxOutputTokens !== undefined\n && (!Number.isSafeInteger(info.maxOutputTokens) || info.maxOutputTokens <= 0)) {\n throw invalidModel(provider, model, 'a non-positive maxOutputTokens')\n }\n if (info.defaultMaxTokens !== undefined && info.maxOutputTokens !== undefined\n && info.defaultMaxTokens > info.maxOutputTokens) {\n throw invalidModel(provider, model, 'defaultMaxTokens above maxOutputTokens')\n }\n if (info.context !== undefined && info.defaultMaxTokens !== undefined\n && info.defaultMaxTokens >= info.context.contextWindow) {\n throw invalidModel(provider, model, 'no input headroom')\n }\n if (info.context !== undefined && info.maxOutputTokens !== undefined\n && info.maxOutputTokens >= (info.context.maxContextWindow ?? info.context.contextWindow)) {\n throw invalidModel(provider, model, 'no input headroom')\n }\n validateReasoning(provider, model, info)\n validateCapabilities(provider, model, info)\n const normalized = deepFreeze(structuredClone({\n ...info,\n ...(info.inputModalities === undefined ? {} : { inputModalities: [...info.inputModalities] }),\n ...(info.outputModalities === undefined ? {} : { outputModalities: [...info.outputModalities] }),\n ...(info.nativeTools === undefined ? {} : { nativeTools: [...info.nativeTools] }),\n }))\n if (serializedBytes(normalized, REGISTRY_ERROR_CODES.INVALID_MODEL_INFO) > maxBytes) {\n throw new ModelError(\n `route \"${provider}\" model metadata exceeds the configured registry limit`,\n REGISTRY_ERROR_CODES.INVALID_MODEL_INFO,\n )\n }\n return normalized\n}\n\nfunction validateReasoning(provider: string, model: string, info: ResolvedModelInfo): void {\n if (info.reasoning === undefined) return\n const ids = info.reasoning.efforts.map(effort => effort.id)\n if (ids.length === 0 || new Set(ids).size !== ids.length\n || info.reasoning.efforts.some(effort =>\n typeof effort.id !== 'string' || effort.id.length === 0\n || typeof effort.name !== 'string' || effort.name.length === 0)) {\n throw invalidModel(provider, model, 'empty or duplicated reasoning efforts')\n }\n if (info.reasoning.defaultEffort !== undefined\n && !ids.includes(info.reasoning.defaultEffort)) {\n throw invalidModel(provider, model, 'a default reasoning effort it does not offer')\n }\n}\n\nfunction validateCapabilities(provider: string, model: string, info: ResolvedModelInfo): void {\n for (const [label, values] of [\n ['input modalities', info.inputModalities],\n ['output modalities', info.outputModalities],\n ['native tools', info.nativeTools],\n ] as const) {\n if (values !== undefined\n && (new Set(values).size !== values.length\n || values.some(value => typeof value !== 'string' || value.length === 0))) {\n throw invalidModel(provider, model, `invalid ${label}`)\n }\n }\n}\n\nfunction invalidModel(provider: string, model: string, reason: string): ModelError {\n return new ModelError(\n `route \"${provider}\" resolved model \"${model}\" with ${reason}`,\n REGISTRY_ERROR_CODES.INVALID_MODEL_INFO,\n )\n}\n\nexport function resolveCallWithModelInfo(\n config: CallConfig,\n info: ResolvedModelInfo,\n): { readonly config: CallConfig; readonly context: ModelContext | undefined } {\n const reasoningEffort = config.reasoningEffort ?? info.reasoning?.defaultEffort\n if (config.reasoningEffort !== undefined\n && info.reasoning?.efforts.some(effort => effort.id === config.reasoningEffort) !== true) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" does not offer reasoning effort `\n + `\"${config.reasoningEffort}\"`,\n REGISTRY_ERROR_CODES.UNSUPPORTED_REASONING_EFFORT,\n )\n }\n const maxTokens = config.maxTokens ?? info.defaultMaxTokens\n if (maxTokens !== undefined && info.maxOutputTokens !== undefined\n && maxTokens > info.maxOutputTokens) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" supports at most `\n + `${info.maxOutputTokens} output tokens, received ${maxTokens}`,\n REGISTRY_ERROR_CODES.OUTPUT_TOKEN_LIMIT_EXCEEDED,\n )\n }\n if (maxTokens !== undefined && info.context !== undefined\n && maxTokens >= info.context.contextWindow) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" cannot reserve ${maxTokens} output tokens `\n + `inside its ${info.context.contextWindow}-token combined context window`,\n REGISTRY_ERROR_CODES.OUTPUT_TOKEN_LIMIT_EXCEEDED,\n )\n }\n return {\n config: {\n provider: config.provider,\n model: config.model,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n ...(config.temperature === undefined ? {} : { temperature: config.temperature }),\n ...(config.topP === undefined ? {} : { topP: config.topP }),\n ...(maxTokens === undefined ? {} : { maxTokens }),\n ...(config.stop === undefined ? {} : { stop: [...config.stop] }),\n },\n context: info.context,\n }\n}\n\nexport function projectReplayForAdapter(\n options: GenerateOptions,\n adapter: ModelAdapter,\n registeredAdapter: (provider: string) => ModelAdapter | undefined,\n): GenerateOptions {\n const messages: Message[] = options.messages.map((message) => {\n const source = message.source\n if (message.role !== 'assistant' || source.kind !== 'model'\n || source.replayState === undefined || registeredAdapter(source.provider) === adapter) {\n return message\n }\n return freezeMessage({\n ...message,\n source: { kind: 'model', provider: source.provider, model: source.model },\n })\n })\n if (messages.every((message, index) => message === options.messages[index])) return options\n return { ...options, messages }\n}\n\nfunction serializedBytes(value: unknown, code: string): number {\n let encoded: string | undefined\n try { encoded = JSON.stringify(value) }\n catch (error) {\n throw new ModelError('adapter model metadata must be JSON-serializable', code, { cause: error })\n }\n if (encoded === undefined) {\n throw new ModelError('adapter model metadata must be JSON-serializable', code)\n }\n return new TextEncoder().encode(encoded).byteLength\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"model-metadata.js","names":[],"sources":["../../src/runtime/model-metadata.ts"],"sourcesContent":["import type { ModelAdapter } from '../contract/adapter.ts'\nimport type { CallConfig } from '../contract/call-config.ts'\nimport type { GenerateOptions } from '../contract/generate-options.ts'\nimport type {\n ModelCatalogSnapshot,\n ModelContext,\n ModelInfo,\n ModelModality,\n ResolvedModelInfo,\n RuntimeDefaults,\n} from '../contract/model-info.ts'\nimport { ModelError, REGISTRY_ERROR_CODES } from '../errors/model-error.ts'\nimport { freezeMessage, type Message } from '../message/message.ts'\nimport { deepFreeze } from '../primitives/freeze.ts'\n\n/**\n * SDK constant of last resort for context capacity: applied only when neither\n * the model, its route, nor {@link RuntimeDefaults.contextWindow} names one.\n */\nexport const DEFAULT_CONTEXT_WINDOW = 200_000\n\n/**\n * SDK constant of last resort for accepted input: applied only when neither\n * the model, its route, nor {@link RuntimeDefaults.inputModalities} names one.\n * Every current modality, because an adapter that stays silent has made no\n * negative capability claim — see {@link ModelInfo.inputModalities}.\n */\nexport const DEFAULT_INPUT_MODALITIES = Object.freeze(['text', 'image', 'document'] as const)\n\nexport function validateCatalogModels(\n provider: string,\n models: readonly ModelInfo[],\n maxModels: number,\n maxBytes: number,\n): ModelInfo[] {\n if (!Array.isArray(models)) {\n throw new ModelError(\n `route \"${provider}\" returned a catalog that is not an array`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n if (models.length > maxModels\n || serializedBytes(models, REGISTRY_ERROR_CODES.INVALID_CATALOG) > maxBytes) {\n throw new ModelError(\n `route \"${provider}\" catalog exceeds the configured registry limit`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n const seen = new Set<string>()\n return models.map((model) => {\n if (model.provider !== provider || typeof model.id !== 'string' || model.id.length === 0\n || typeof model.name !== 'string' || model.name.length === 0) {\n throw new ModelError(\n `route \"${provider}\" advertised a model entry with invalid identity`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n if (seen.has(model.id)) {\n throw new ModelError(\n `route \"${provider}\" advertised model \"${model.id}\" more than once`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n seen.add(model.id)\n return structuredClone(model)\n })\n}\n\nexport function validateModelCatalogSnapshot(\n provider: string,\n snapshot: ModelCatalogSnapshot,\n maxModels: number,\n maxBytes: number,\n): ModelCatalogSnapshot {\n if (typeof snapshot !== 'object' || snapshot === null\n || snapshot.provider?.id !== provider || typeof snapshot.provider.name !== 'string'\n || snapshot.provider.name.length === 0\n || !['static', 'fresh', 'empty', 'stale', 'unavailable'].includes(snapshot.state)\n || typeof snapshot.revision !== 'string' || snapshot.revision.length === 0\n || typeof snapshot.observedAt !== 'string' || !Number.isFinite(Date.parse(snapshot.observedAt))) {\n throw new ModelError(\n `route \"${provider}\" returned an invalid catalog snapshot`,\n REGISTRY_ERROR_CODES.INVALID_CATALOG,\n )\n }\n const models = validateCatalogModels(provider, snapshot.models, maxModels, maxBytes)\n return deepFreeze({ ...structuredClone(snapshot), provider: { ...snapshot.provider }, models })\n}\n\nexport function normalizeResolvedModelInfo(\n provider: string,\n model: string,\n info: ResolvedModelInfo,\n maxBytes: number,\n defaults: RuntimeDefaults = {},\n): ResolvedModelInfo {\n if (info.provider !== provider || info.id !== model\n || typeof info.name !== 'string' || info.name.length === 0) {\n throw invalidModel(provider, model, 'mismatched identity')\n }\n if (info.context !== undefined\n && (!Number.isSafeInteger(info.context.contextWindow) || info.context.contextWindow <= 0)) {\n throw invalidModel(provider, model, 'a non-positive context window')\n }\n if (info.defaultMaxTokens !== undefined\n && (!Number.isSafeInteger(info.defaultMaxTokens) || info.defaultMaxTokens <= 0)) {\n throw invalidModel(provider, model, 'a non-positive defaultMaxTokens')\n }\n for (const value of [info.context?.maxContextWindow, info.context?.defaultContextWindow, info.context?.standardPriceInputTokens]) {\n if (value !== undefined && (!Number.isSafeInteger(value) || value <= 0)) {\n throw invalidModel(provider, model, 'invalid context policy')\n }\n }\n if (info.context?.maxContextWindow !== undefined && (\n info.context.contextWindow > info.context.maxContextWindow\n || (info.context.defaultContextWindow ?? 0) > info.context.maxContextWindow\n )) throw invalidModel(provider, model, 'contextWindow above maxContextWindow')\n if (info.maxOutputTokens !== undefined\n && (!Number.isSafeInteger(info.maxOutputTokens) || info.maxOutputTokens <= 0)) {\n throw invalidModel(provider, model, 'a non-positive maxOutputTokens')\n }\n if (info.defaultMaxTokens !== undefined && info.maxOutputTokens !== undefined\n && info.defaultMaxTokens > info.maxOutputTokens) {\n throw invalidModel(provider, model, 'defaultMaxTokens above maxOutputTokens')\n }\n if (info.context !== undefined && info.defaultMaxTokens !== undefined\n && info.defaultMaxTokens >= info.context.contextWindow) {\n throw invalidModel(provider, model, 'no input headroom')\n }\n if (info.context !== undefined && info.maxOutputTokens !== undefined\n && info.maxOutputTokens >= (info.context.maxContextWindow ?? info.context.contextWindow)) {\n throw invalidModel(provider, model, 'no input headroom')\n }\n validateReasoning(provider, model, info)\n validateCapabilities(provider, model, info)\n // Fill what the adapter left silent, in priority order: the route/model\n // already spoke through `info` above, so only a genuine gap reaches here —\n // the runtime's own defaults, then the SDK's last-resort constant. Neither\n // ever overrides a fact the adapter actually declared.\n const contextWindow = info.context?.contextWindow ?? defaults.contextWindow ?? DEFAULT_CONTEXT_WINDOW\n const inputModalities = info.inputModalities ?? defaults.inputModalities ?? DEFAULT_INPUT_MODALITIES\n const normalized = deepFreeze(structuredClone({\n ...info,\n context: { ...info.context, contextWindow },\n inputModalities: [...inputModalities],\n ...(info.outputModalities === undefined ? {} : { outputModalities: [...info.outputModalities] }),\n ...(info.nativeTools === undefined ? {} : { nativeTools: [...info.nativeTools] }),\n }))\n if (serializedBytes(normalized, REGISTRY_ERROR_CODES.INVALID_MODEL_INFO) > maxBytes) {\n throw new ModelError(\n `route \"${provider}\" model metadata exceeds the configured registry limit`,\n REGISTRY_ERROR_CODES.INVALID_MODEL_INFO,\n )\n }\n return normalized\n}\n\n/** Structural check only: `reasoning` is advisory display metadata, never a dispatch gate. */\nfunction validateReasoning(provider: string, model: string, info: ResolvedModelInfo): void {\n if (info.reasoning === undefined) return\n const ids = info.reasoning.efforts.map(effort => effort.id)\n if (ids.length === 0 || new Set(ids).size !== ids.length\n || info.reasoning.efforts.some(effort =>\n typeof effort.id !== 'string' || effort.id.length === 0\n || typeof effort.name !== 'string' || effort.name.length === 0)) {\n throw invalidModel(provider, model, 'empty or duplicated reasoning efforts')\n }\n}\n\nfunction validateCapabilities(provider: string, model: string, info: ResolvedModelInfo): void {\n for (const [label, values] of [\n ['input modalities', info.inputModalities],\n ['output modalities', info.outputModalities],\n ['native tools', info.nativeTools],\n ] as const) {\n if (values !== undefined\n && (new Set(values).size !== values.length\n || values.some(value => typeof value !== 'string' || value.length === 0))) {\n throw invalidModel(provider, model, `invalid ${label}`)\n }\n }\n}\n\nfunction invalidModel(provider: string, model: string, reason: string): ModelError {\n return new ModelError(\n `route \"${provider}\" resolved model \"${model}\" with ${reason}`,\n REGISTRY_ERROR_CODES.INVALID_MODEL_INFO,\n )\n}\n\nexport function resolveCallWithModelInfo(\n config: CallConfig,\n info: ResolvedModelInfo,\n defaults: RuntimeDefaults = {},\n): {\n readonly config: CallConfig\n readonly context: ModelContext | undefined\n readonly inputModalities: readonly ModelModality[] | undefined\n} {\n // Pass-through: the registry neither validates a caller's effort against\n // `info.reasoning` nor materializes one the caller omitted. An unsupported\n // value is the provider's call to make, at dispatch, in its own error shape.\n const reasoningEffort = config.reasoningEffort\n // Agent tier (1) wins over whatever normalizeResolvedModelInfo already\n // resolved (model/route/runtime-defaults/SDK-constant, tiers 2-5) — same\n // precedence rule as maxTokens below, just one tier higher since the model\n // itself never names an override for its own capacity.\n const context = config.contextWindow === undefined || info.context === undefined\n ? info.context\n : { ...info.context, contextWindow: config.contextWindow }\n if (context !== undefined && context.maxContextWindow !== undefined\n && context.contextWindow > context.maxContextWindow) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" was asked for a ${context.contextWindow}-token `\n + `context window, above its ${context.maxContextWindow}-token technical ceiling`,\n REGISTRY_ERROR_CODES.INVALID_MODEL_INFO,\n )\n }\n const inputModalities = config.inputModalities ?? info.inputModalities\n // maxTokens has no SDK-constant tier: unlike context/modalities, an unset\n // output cap is not sent at all rather than defaulted (see RuntimeDefaults).\n const maxTokens = config.maxTokens ?? info.defaultMaxTokens ?? defaults.maxTokens\n if (maxTokens !== undefined && info.maxOutputTokens !== undefined\n && maxTokens > info.maxOutputTokens) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" supports at most `\n + `${info.maxOutputTokens} output tokens, received ${maxTokens}`,\n REGISTRY_ERROR_CODES.OUTPUT_TOKEN_LIMIT_EXCEEDED,\n )\n }\n if (maxTokens !== undefined && context !== undefined\n && maxTokens >= context.contextWindow) {\n throw new ModelError(\n `model \"${info.id}\" on route \"${info.provider}\" cannot reserve ${maxTokens} output tokens `\n + `inside its ${context.contextWindow}-token combined context window`,\n REGISTRY_ERROR_CODES.OUTPUT_TOKEN_LIMIT_EXCEEDED,\n )\n }\n return {\n config: {\n provider: config.provider,\n model: config.model,\n ...(reasoningEffort === undefined ? {} : { reasoningEffort }),\n ...(config.temperature === undefined ? {} : { temperature: config.temperature }),\n ...(config.topP === undefined ? {} : { topP: config.topP }),\n ...(maxTokens === undefined ? {} : { maxTokens }),\n ...(config.stop === undefined ? {} : { stop: [...config.stop] }),\n ...(config.contextWindow === undefined ? {} : { contextWindow: config.contextWindow }),\n ...(config.inputModalities === undefined ? {} : { inputModalities: [...config.inputModalities] }),\n },\n context,\n inputModalities,\n }\n}\n\nexport function projectReplayForAdapter(\n options: GenerateOptions,\n adapter: ModelAdapter,\n registeredAdapter: (provider: string) => ModelAdapter | undefined,\n): GenerateOptions {\n const messages: Message[] = options.messages.map((message) => {\n const source = message.source\n if (message.role !== 'assistant' || source.kind !== 'model'\n || source.replayState === undefined || registeredAdapter(source.provider) === adapter) {\n return message\n }\n return freezeMessage({\n ...message,\n source: { kind: 'model', provider: source.provider, model: source.model },\n })\n })\n if (messages.every((message, index) => message === options.messages[index])) return options\n return { ...options, messages }\n}\n\nfunction serializedBytes(value: unknown, code: string): number {\n let encoded: string | undefined\n try { encoded = JSON.stringify(value) }\n catch (error) {\n throw new ModelError('adapter model metadata must be JSON-serializable', code, { cause: error })\n }\n if (encoded === undefined) {\n throw new ModelError('adapter model metadata must be JSON-serializable', code)\n }\n return new TextEncoder().encode(encoded).byteLength\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{waitForSettlement as e}from"../async/settlement.js";import{MODEL_ERROR_CODES as t,ModelError as n,REGISTRY_ERROR_CODES as r}from"../errors/model-error.js";import{normalizeModelFailure as i}from"../errors/failure.js";import{contentHasDocument as a,contentHasImage as o,projectDocumentsForTextModel as s,projectImagesForTextModel as c}from"../message/projection.js";import{callConfigEquals as l}from"../contract/call-config.js";import{isNativeToolSchema as u}from"../contract/tool.js";import{normalizeResolvedModelInfo as d,projectReplayForAdapter as f,resolveCallWithModelInfo as p}from"./model-metadata.js";async function*m(e){let{options:t,context:r}=e,i;try{let u=e.prepared?.registration??e.registration(t.provider),d=u.adapter,p=await h(e,u,d),m=l(t,p.config)?t:{...t,...p.config},_=p.modelInfo.inputModalities!==void 0&&!p.modelInfo.inputModalities.includes(`image`)&&m.messages.some(e=>o(e.content)),v=p.modelInfo.inputModalities!==void 0&&!p.modelInfo.inputModalities.includes(`document`)&&m.messages.some(e=>a(e.content));if(m.imagePolicy!==void 0&&m.imagePolicy!==`strict`&&m.imagePolicy!==`project`)throw new n(`invalid image policy`,`INVALID_IMAGE_POLICY`);if(m.documentPolicy!==void 0&&m.documentPolicy!==`strict`&&m.documentPolicy!==`project`)throw new n(`invalid document policy`,`INVALID_DOCUMENT_POLICY`);if(_&&m.imagePolicy===`strict`)throw new n(`model ${p.modelInfo.id} does not support required image input`,`UNSUPPORTED_IMAGE_INPUT`);if(v&&m.documentPolicy===`strict`)throw new n(`model ${p.modelInfo.id} does not support required document input`,`UNSUPPORTED_DOCUMENT_INPUT`);let y=_?{...m,messages:c(m.messages)}:m,b=v?{...y,messages:s(y.messages)}:y;g(b,p.modelInfo),e.onDispatch(),i=p.dispatch(f(b,d,e.registeredAdapter),r)[Symbol.asyncIterator]()}catch(e){yield y(e,t.signal);return}yield*_(i,t.signal)}async function h(e,t,i){let{options:a,context:o,prepared:s}=e;if(s!==void 0){if(!l(a,s.config))throw new n(`prepared call config changed before adapter dispatch`,r.INVALID_PREPARED_CALL);return{modelInfo:s.modelInfo,config:s.config,dispatch:s.dispatch}}let c=await i.prepareCall(a.provider,a.model,a.signal,o),u=d(t.provider.id,a.model,c.model,e.maxCatalogBytes);return{modelInfo:u,config:p(a,u).config,dispatch:(e,t)=>c.stream(e,t)}}function g(e,t){if(t.nativeTools!==void 0){for(let i of e.tools??[])if(u(i)&&!t.nativeTools.includes(i.name))throw new n(`model "${t.id}" on route "${t.provider}" does not support native tool "${i.name}"`,r.UNSUPPORTED_NATIVE_TOOL)}}async function*_(e,t){let n=!1;try{for(;;){let r;try{let t=await e.next();r=t.done===!0?{done:!0}:{done:!1,value:t.value}}catch(e){n=!0,yield y(e,t);return}if(r.done){n=!0;return}yield r.value}}finally{n||await v(e)}}async function v(r){let i=r.return?.bind(r);if(i===void 0)return;let a=Promise.resolve().then(async()=>{await i()});if(!await e(a,3e4))throw new n(`model adapter ignored cancellation for more than 30000ms`,t.TEARDOWN_TIMEOUT)}function y(e,t){let n=i(e);return{type:`finish`,reason:t?.aborted===!0||n.code===`ABORTED`?{kind:`aborted`,failure:n}:{kind:`error`,failure:n}}}export{m as streamAdapter};
1
+ import{waitForSettlement as e}from"../async/settlement.js";import{MODEL_ERROR_CODES as t,ModelError as n,REGISTRY_ERROR_CODES as r}from"../errors/model-error.js";import{normalizeModelFailure as i}from"../errors/failure.js";import{contentHasDocument as a,contentHasImage as o,projectDocumentsForTextModel as s,projectImagesForTextModel as c}from"../message/projection.js";import{callConfigEquals as l}from"../contract/call-config.js";import{isNativeToolSchema as u}from"../contract/tool.js";import{normalizeResolvedModelInfo as d,projectReplayForAdapter as f,resolveCallWithModelInfo as p}from"./model-metadata.js";async function*m(e){let{options:t,context:r}=e,i;try{let u=e.prepared?.registration??e.registration(t.provider),d=u.adapter,p=await h(e,u,d),m=l(t,p.config)?t:{...t,...p.config},_=m.inputModalities??p.modelInfo.inputModalities,v=_!==void 0&&!_.includes(`image`)&&m.messages.some(e=>o(e.content)),y=_!==void 0&&!_.includes(`document`)&&m.messages.some(e=>a(e.content));if(m.imagePolicy!==void 0&&m.imagePolicy!==`strict`&&m.imagePolicy!==`project`)throw new n(`invalid image policy`,`INVALID_IMAGE_POLICY`);if(m.documentPolicy!==void 0&&m.documentPolicy!==`strict`&&m.documentPolicy!==`project`)throw new n(`invalid document policy`,`INVALID_DOCUMENT_POLICY`);if(v&&m.imagePolicy===`strict`)throw new n(`model ${p.modelInfo.id} does not support required image input`,`UNSUPPORTED_IMAGE_INPUT`);if(y&&m.documentPolicy===`strict`)throw new n(`model ${p.modelInfo.id} does not support required document input`,`UNSUPPORTED_DOCUMENT_INPUT`);let b=v?{...m,messages:c(m.messages)}:m,x=y?{...b,messages:s(b.messages)}:b;g(x,p.modelInfo),e.onDispatch(),i=p.dispatch(f(x,d,e.registeredAdapter),r)[Symbol.asyncIterator]()}catch(e){yield y(e,t.signal);return}yield*_(i,t.signal)}async function h(e,t,i){let{options:a,context:o,prepared:s}=e;if(s!==void 0){if(!l(a,s.config))throw new n(`prepared call config changed before adapter dispatch`,r.INVALID_PREPARED_CALL);return{modelInfo:s.modelInfo,config:s.config,dispatch:s.dispatch}}let c=await i.prepareCall(a.provider,a.model,a.signal,o),u=d(t.provider.id,a.model,c.model,e.maxCatalogBytes,e.defaults);return{modelInfo:u,config:p(a,u,e.defaults).config,dispatch:(e,t)=>c.stream(e,t)}}function g(e,t){if(t.nativeTools!==void 0){for(let i of e.tools??[])if(u(i)&&!t.nativeTools.includes(i.name))throw new n(`model "${t.id}" on route "${t.provider}" does not support native tool "${i.name}"`,r.UNSUPPORTED_NATIVE_TOOL)}}async function*_(e,t){let n=!1;try{for(;;){let r;try{let t=await e.next();r=t.done===!0?{done:!0}:{done:!1,value:t.value}}catch(e){n=!0,yield y(e,t);return}if(r.done){n=!0;return}yield r.value}}finally{n||await v(e)}}async function v(r){let i=r.return?.bind(r);if(i===void 0)return;let a=Promise.resolve().then(async()=>{await i()});if(!await e(a,3e4))throw new n(`model adapter ignored cancellation for more than 30000ms`,t.TEARDOWN_TIMEOUT)}function y(e,t){let n=i(e);return{type:`finish`,reason:t?.aborted===!0||n.code===`ABORTED`?{kind:`aborted`,failure:n}:{kind:`error`,failure:n}}}export{m as streamAdapter};
2
2
  //# sourceMappingURL=model-stream.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"model-stream.js","names":[],"sources":["../../src/runtime/model-stream.ts"],"sourcesContent":["import type { ModelAdapter, PreparedAdapterCall } from '../contract/adapter.ts'\nimport { callConfigEquals, type CallConfig } from '../contract/call-config.ts'\nimport type { GenerateOptions } from '../contract/generate-options.ts'\nimport { isNativeToolSchema } from '../contract/tool.ts'\nimport type { ProviderInfo, ResolvedModelInfo } from '../contract/model-info.ts'\nimport type { ResolvedRetryPolicy } from '../contract/retry-policy.ts'\nimport { normalizeModelFailure } from '../errors/failure.ts'\nimport { MODEL_ERROR_CODES, ModelError, REGISTRY_ERROR_CODES } from '../errors/model-error.ts'\nimport {\n contentHasDocument, contentHasImage, projectDocumentsForTextModel, projectImagesForTextModel,\n} from '../message/projection.ts'\nimport type { ModelInvocationContext } from '../observation/report.ts'\nimport type { StreamChunk } from '../stream/chunk.ts'\nimport { waitForSettlement } from '../async/settlement.ts'\nimport {\n normalizeResolvedModelInfo,\n projectReplayForAdapter,\n resolveCallWithModelInfo,\n} from './model-metadata.ts'\n\nexport interface RuntimeAdapterRegistration {\n readonly adapter: ModelAdapter\n readonly provider: ProviderInfo\n readonly retryPolicy: ResolvedRetryPolicy\n readonly pluginId?: string\n readonly family?: string\n}\n\nexport interface PreparedDispatch {\n readonly registration: RuntimeAdapterRegistration\n readonly config: CallConfig\n readonly modelInfo: ResolvedModelInfo\n readonly dispatch: (options: GenerateOptions, context: ModelInvocationContext) => AsyncIterable<StreamChunk>\n}\n\nexport interface AdapterStreamInput {\n readonly options: GenerateOptions\n readonly context: ModelInvocationContext\n readonly onDispatch: () => void\n readonly prepared?: PreparedDispatch\n readonly maxCatalogBytes: number\n readonly registration: (provider: string) => RuntimeAdapterRegistration\n readonly registeredAdapter: (provider: string) => ModelAdapter | undefined\n}\n\n/** Run one adapter generation through the registry's single failure/cancellation funnel. */\nexport async function* streamAdapter(input: AdapterStreamInput): AsyncGenerator<StreamChunk> {\n const { options, context } = input\n let iterator: AsyncIterator<StreamChunk>\n try {\n const registration = input.prepared?.registration ?? input.registration(options.provider)\n const adapter = registration.adapter\n const prepared = await prepareDispatch(input, registration, adapter)\n const withConfig = callConfigEquals(options, prepared.config)\n ? options\n : { ...options, ...prepared.config }\n const hasUnsupportedImages = prepared.modelInfo.inputModalities !== undefined\n && !prepared.modelInfo.inputModalities.includes('image')\n && withConfig.messages.some(message => contentHasImage(message.content))\n const hasUnsupportedDocuments = prepared.modelInfo.inputModalities !== undefined\n && !prepared.modelInfo.inputModalities.includes('document')\n && withConfig.messages.some(message => contentHasDocument(message.content))\n if (withConfig.imagePolicy !== undefined && withConfig.imagePolicy !== 'strict' && withConfig.imagePolicy !== 'project') throw new ModelError('invalid image policy', 'INVALID_IMAGE_POLICY')\n if (withConfig.documentPolicy !== undefined && withConfig.documentPolicy !== 'strict' && withConfig.documentPolicy !== 'project') throw new ModelError('invalid document policy', 'INVALID_DOCUMENT_POLICY')\n if (hasUnsupportedImages && withConfig.imagePolicy === 'strict') throw new ModelError(\n `model ${prepared.modelInfo.id} does not support required image input`, 'UNSUPPORTED_IMAGE_INPUT',\n )\n if (hasUnsupportedDocuments && withConfig.documentPolicy === 'strict') throw new ModelError(\n `model ${prepared.modelInfo.id} does not support required document input`, 'UNSUPPORTED_DOCUMENT_INPUT',\n )\n const withImages = hasUnsupportedImages\n ? { ...withConfig, messages: projectImagesForTextModel(withConfig.messages) }\n : withConfig\n const projected = hasUnsupportedDocuments\n ? { ...withImages, messages: projectDocumentsForTextModel(withImages.messages) }\n : withImages\n validateNativeTools(projected, prepared.modelInfo)\n input.onDispatch()\n iterator = prepared.dispatch(projectReplayForAdapter(\n projected, adapter, input.registeredAdapter,\n ), context)[Symbol.asyncIterator]()\n } catch (error: unknown) {\n yield adapterFailureChunk(error, options.signal)\n return\n }\n yield* consumeIterator(iterator, options.signal)\n}\n\nasync function prepareDispatch(\n input: AdapterStreamInput,\n registration: RuntimeAdapterRegistration,\n adapter: ModelAdapter,\n): Promise<{ readonly modelInfo: ResolvedModelInfo; readonly config: CallConfig;\n readonly dispatch: PreparedDispatch['dispatch'] }> {\n const { options, context, prepared } = input\n if (prepared !== undefined) {\n if (!callConfigEquals(options, prepared.config)) {\n throw new ModelError(\n 'prepared call config changed before adapter dispatch',\n REGISTRY_ERROR_CODES.INVALID_PREPARED_CALL,\n )\n }\n return { modelInfo: prepared.modelInfo, config: prepared.config, dispatch: prepared.dispatch }\n }\n const adapterCall: PreparedAdapterCall = await adapter.prepareCall(\n options.provider, options.model, options.signal, context,\n )\n const modelInfo = normalizeResolvedModelInfo(\n registration.provider.id, options.model, adapterCall.model, input.maxCatalogBytes,\n )\n return {\n modelInfo,\n config: resolveCallWithModelInfo(options, modelInfo).config,\n dispatch: (request, activeContext) => adapterCall.stream(request, activeContext),\n }\n}\n\nfunction validateNativeTools(options: GenerateOptions, model: ResolvedModelInfo): void {\n if (model.nativeTools === undefined) return\n for (const tool of options.tools ?? []) {\n if (isNativeToolSchema(tool) && !model.nativeTools.includes(tool.name)) {\n throw new ModelError(\n `model \"${model.id}\" on route \"${model.provider}\" does not support native tool \"${tool.name}\"`,\n REGISTRY_ERROR_CODES.UNSUPPORTED_NATIVE_TOOL,\n )\n }\n }\n}\n\nasync function* consumeIterator(\n iterator: AsyncIterator<StreamChunk>,\n signal?: AbortSignal,\n): AsyncGenerator<StreamChunk> {\n let completed = false\n try {\n while (true) {\n let item: { done: true } | { done: false; value: StreamChunk }\n try {\n const next = await iterator.next()\n item = next.done === true ? { done: true } : { done: false, value: next.value }\n } catch (error: unknown) {\n completed = true\n yield adapterFailureChunk(error, signal)\n return\n }\n if (item.done) { completed = true; return }\n yield item.value\n }\n } finally {\n if (!completed) await closeIterator(iterator)\n }\n}\n\nasync function closeIterator(iterator: AsyncIterator<StreamChunk>): Promise<void> {\n const close = iterator.return?.bind(iterator)\n if (close === undefined) return\n const closing = Promise.resolve().then(async () => { await close() })\n if (!await waitForSettlement(closing, 30_000)) {\n throw new ModelError(\n 'model adapter ignored cancellation for more than 30000ms',\n MODEL_ERROR_CODES.TEARDOWN_TIMEOUT,\n )\n }\n}\n\nfunction adapterFailureChunk(error: unknown, signal?: AbortSignal): StreamChunk {\n const failure = normalizeModelFailure(error)\n return {\n type: 'finish',\n reason: signal?.aborted === true || failure.code === 'ABORTED'\n ? { kind: 'aborted', failure }\n : { kind: 'error', failure },\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"model-stream.js","names":[],"sources":["../../src/runtime/model-stream.ts"],"sourcesContent":["import type { ModelAdapter, PreparedAdapterCall } from '../contract/adapter.ts'\nimport { callConfigEquals, type CallConfig } from '../contract/call-config.ts'\nimport type { GenerateOptions } from '../contract/generate-options.ts'\nimport { isNativeToolSchema } from '../contract/tool.ts'\nimport type { ProviderInfo, ResolvedModelInfo, RuntimeDefaults } from '../contract/model-info.ts'\nimport type { ResolvedRetryPolicy } from '../contract/retry-policy.ts'\nimport { normalizeModelFailure } from '../errors/failure.ts'\nimport { MODEL_ERROR_CODES, ModelError, REGISTRY_ERROR_CODES } from '../errors/model-error.ts'\nimport {\n contentHasDocument, contentHasImage, projectDocumentsForTextModel, projectImagesForTextModel,\n} from '../message/projection.ts'\nimport type { ModelInvocationContext } from '../observation/report.ts'\nimport type { StreamChunk } from '../stream/chunk.ts'\nimport { waitForSettlement } from '../async/settlement.ts'\nimport {\n normalizeResolvedModelInfo,\n projectReplayForAdapter,\n resolveCallWithModelInfo,\n} from './model-metadata.ts'\n\nexport interface RuntimeAdapterRegistration {\n readonly adapter: ModelAdapter\n readonly provider: ProviderInfo\n readonly retryPolicy: ResolvedRetryPolicy\n readonly pluginId?: string\n readonly family?: string\n}\n\nexport interface PreparedDispatch {\n readonly registration: RuntimeAdapterRegistration\n readonly config: CallConfig\n readonly modelInfo: ResolvedModelInfo\n readonly dispatch: (options: GenerateOptions, context: ModelInvocationContext) => AsyncIterable<StreamChunk>\n}\n\nexport interface AdapterStreamInput {\n readonly options: GenerateOptions\n readonly context: ModelInvocationContext\n readonly onDispatch: () => void\n readonly prepared?: PreparedDispatch\n readonly maxCatalogBytes: number\n readonly defaults: RuntimeDefaults\n readonly registration: (provider: string) => RuntimeAdapterRegistration\n readonly registeredAdapter: (provider: string) => ModelAdapter | undefined\n}\n\n/** Run one adapter generation through the registry's single failure/cancellation funnel. */\nexport async function* streamAdapter(input: AdapterStreamInput): AsyncGenerator<StreamChunk> {\n const { options, context } = input\n let iterator: AsyncIterator<StreamChunk>\n try {\n const registration = input.prepared?.registration ?? input.registration(options.provider)\n const adapter = registration.adapter\n const prepared = await prepareDispatch(input, registration, adapter)\n const withConfig = callConfigEquals(options, prepared.config)\n ? options\n : { ...options, ...prepared.config }\n // The agent tier (CallConfig.inputModalities, folded into `withConfig` by\n // `resolveCallWithModelInfo`) wins over the model's own declared value.\n const effectiveInputModalities = withConfig.inputModalities ?? prepared.modelInfo.inputModalities\n const hasUnsupportedImages = effectiveInputModalities !== undefined\n && !effectiveInputModalities.includes('image')\n && withConfig.messages.some(message => contentHasImage(message.content))\n const hasUnsupportedDocuments = effectiveInputModalities !== undefined\n && !effectiveInputModalities.includes('document')\n && withConfig.messages.some(message => contentHasDocument(message.content))\n if (withConfig.imagePolicy !== undefined && withConfig.imagePolicy !== 'strict' && withConfig.imagePolicy !== 'project') throw new ModelError('invalid image policy', 'INVALID_IMAGE_POLICY')\n if (withConfig.documentPolicy !== undefined && withConfig.documentPolicy !== 'strict' && withConfig.documentPolicy !== 'project') throw new ModelError('invalid document policy', 'INVALID_DOCUMENT_POLICY')\n if (hasUnsupportedImages && withConfig.imagePolicy === 'strict') throw new ModelError(\n `model ${prepared.modelInfo.id} does not support required image input`, 'UNSUPPORTED_IMAGE_INPUT',\n )\n if (hasUnsupportedDocuments && withConfig.documentPolicy === 'strict') throw new ModelError(\n `model ${prepared.modelInfo.id} does not support required document input`, 'UNSUPPORTED_DOCUMENT_INPUT',\n )\n const withImages = hasUnsupportedImages\n ? { ...withConfig, messages: projectImagesForTextModel(withConfig.messages) }\n : withConfig\n const projected = hasUnsupportedDocuments\n ? { ...withImages, messages: projectDocumentsForTextModel(withImages.messages) }\n : withImages\n validateNativeTools(projected, prepared.modelInfo)\n input.onDispatch()\n iterator = prepared.dispatch(projectReplayForAdapter(\n projected, adapter, input.registeredAdapter,\n ), context)[Symbol.asyncIterator]()\n } catch (error: unknown) {\n yield adapterFailureChunk(error, options.signal)\n return\n }\n yield* consumeIterator(iterator, options.signal)\n}\n\nasync function prepareDispatch(\n input: AdapterStreamInput,\n registration: RuntimeAdapterRegistration,\n adapter: ModelAdapter,\n): Promise<{ readonly modelInfo: ResolvedModelInfo; readonly config: CallConfig;\n readonly dispatch: PreparedDispatch['dispatch'] }> {\n const { options, context, prepared } = input\n if (prepared !== undefined) {\n if (!callConfigEquals(options, prepared.config)) {\n throw new ModelError(\n 'prepared call config changed before adapter dispatch',\n REGISTRY_ERROR_CODES.INVALID_PREPARED_CALL,\n )\n }\n return { modelInfo: prepared.modelInfo, config: prepared.config, dispatch: prepared.dispatch }\n }\n const adapterCall: PreparedAdapterCall = await adapter.prepareCall(\n options.provider, options.model, options.signal, context,\n )\n const modelInfo = normalizeResolvedModelInfo(\n registration.provider.id, options.model, adapterCall.model, input.maxCatalogBytes, input.defaults,\n )\n return {\n modelInfo,\n config: resolveCallWithModelInfo(options, modelInfo, input.defaults).config,\n dispatch: (request, activeContext) => adapterCall.stream(request, activeContext),\n }\n}\n\nfunction validateNativeTools(options: GenerateOptions, model: ResolvedModelInfo): void {\n if (model.nativeTools === undefined) return\n for (const tool of options.tools ?? []) {\n if (isNativeToolSchema(tool) && !model.nativeTools.includes(tool.name)) {\n throw new ModelError(\n `model \"${model.id}\" on route \"${model.provider}\" does not support native tool \"${tool.name}\"`,\n REGISTRY_ERROR_CODES.UNSUPPORTED_NATIVE_TOOL,\n )\n }\n }\n}\n\nasync function* consumeIterator(\n iterator: AsyncIterator<StreamChunk>,\n signal?: AbortSignal,\n): AsyncGenerator<StreamChunk> {\n let completed = false\n try {\n while (true) {\n let item: { done: true } | { done: false; value: StreamChunk }\n try {\n const next = await iterator.next()\n item = next.done === true ? { done: true } : { done: false, value: next.value }\n } catch (error: unknown) {\n completed = true\n yield adapterFailureChunk(error, signal)\n return\n }\n if (item.done) { completed = true; return }\n yield item.value\n }\n } finally {\n if (!completed) await closeIterator(iterator)\n }\n}\n\nasync function closeIterator(iterator: AsyncIterator<StreamChunk>): Promise<void> {\n const close = iterator.return?.bind(iterator)\n if (close === undefined) return\n const closing = Promise.resolve().then(async () => { await close() })\n if (!await waitForSettlement(closing, 30_000)) {\n throw new ModelError(\n 'model adapter ignored cancellation for more than 30000ms',\n MODEL_ERROR_CODES.TEARDOWN_TIMEOUT,\n )\n }\n}\n\nfunction adapterFailureChunk(error: unknown, signal?: AbortSignal): StreamChunk {\n const failure = normalizeModelFailure(error)\n return {\n type: 'finish',\n reason: signal?.aborted === true || failure.code === 'ABORTED'\n ? { kind: 'aborted', failure }\n : { kind: 'error', failure },\n }\n}\n"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import { ObservationResource } from "../observation/event.js";
2
2
  import { ObservationPort } from "../observation/port.js";
3
3
  import { ModelCallHandle, ModelInvocationContext } from "../observation/report.js";
4
+ import { ModelCatalogOptions, ModelCatalogSnapshot, ModelContext, ModelInfo, ModelModality, ProviderInfo, ResolvedModelInfo, RuntimeDefaults } from "../contract/model-info.js";
4
5
  import { GenerateOptions } from "../contract/generate-options.js";
5
- import { ModelCatalogOptions, ModelCatalogSnapshot, ModelContext, ModelInfo, ModelModality, ProviderInfo, ResolvedModelInfo } from "../contract/model-info.js";
6
6
  import { ResolvedRetryPolicy } from "../contract/retry-policy.js";
7
7
  import { ModelAdapter } from "../contract/adapter.js";
8
8
  import { CallConfig, CallConfigAdapterDefaults } from "../contract/call-config.js";
@@ -45,6 +45,11 @@ interface ModelRegistryOptions {
45
45
  readonly observation?: ObservationPort;
46
46
  /** Safe SDK/service/runtime identity copied onto observation events. */
47
47
  readonly observationResource?: ObservationResource;
48
+ /**
49
+ * SDK-wide fallbacks (context window, output cap, accepted modalities) used
50
+ * only when neither a model nor its route names one. See {@link RuntimeDefaults}.
51
+ */
52
+ readonly defaults?: RuntimeDefaults;
48
53
  }
49
54
  /**
50
55
  * Routes model calls to registered adapters.
@@ -61,6 +66,7 @@ declare class ModelRegistry {
61
66
  private readonly maxCatalogBytes;
62
67
  private readonly observation;
63
68
  private readonly observationResource;
69
+ private readonly defaults;
64
70
  constructor(options?: ModelRegistryOptions);
65
71
  /** Install one provider plugin as a single synchronous topology transaction. */
66
72
  install(plugin: ModelProviderPlugin): PluginRegistrationHandle;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","names":[],"sources":["../../src/runtime/registry.ts"],"mappings":";;;;;;;;;;;;;;;;;;UA6DiB;;WAEN,QAAQ;;WAER,aAAa;;WAEb,UAAU;;WAEV,2BAA2B;;WAE3B,OAAO;;WAEP,iBAAiB;;;;;;EAM1B,OAAO,SAAS,iBAAiB,UAAU,yBAAyB;;UAGrD;;WAEN;;WAEA;;WAEA,cAAc;;WAEd,sBAAsB;;;;;;;;cA0CpB;UACH;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;EAEjB,YAAY,UAAS;;EAYrB,QAAQ,QAAQ,sBAAsB;;;;;;;;;;EAoJtC,gBACE,8BACA,SAAS,eACR;;;;;;UA0CK;;;;;UA+CA;;;;;;EAkBR,IAAI,YAAY;;;;;;EAahB,kBAAkB;;;;;;;;UAYV;;;;;EAcR,iBAAiB;;;;;;;;;EAYX,WAAW,kBAAkB,SAAS,cAAc,QAAQ;;EAO5D,aAAa,kBAAkB,UAAS,sBAA2B,QAAQ;;;;;;;;EAa3E,iBACJ,kBACA,eACA,SAAS,cACR,QAAQ;;EAOX,YAAY,mBAAmB;;;;;;;;EAWzB,YACJ,QAAQ,YACR,SAAS,aACT,oBAAoB,yBACnB,QAAQ;;;;;;;;;;;EAmEX,OAAO,SAAS,iBAAiB,UAAU,yBAAyB;UAI5D;;;;;;;;;;;;;UAyCA;UA6BA"}
1
+ {"version":3,"file":"registry.d.ts","names":[],"sources":["../../src/runtime/registry.ts"],"mappings":";;;;;;;;;;;;;;;;;;UA8DiB;;WAEN,QAAQ;;WAER,aAAa;;WAEb,UAAU;;WAEV,2BAA2B;;WAE3B,OAAO;;WAEP,iBAAiB;;;;;;EAM1B,OAAO,SAAS,iBAAiB,UAAU,yBAAyB;;UAGrD;;WAEN;;WAEA;;WAEA,cAAc;;WAEd,sBAAsB;;;;;WAKtB,WAAW;;;;;;;;cA0CT;UACH;UACA;UACA;UACA;mBACS;mBACA;mBACA;mBACA;mBACA;EAEjB,YAAY,UAAS;;EAarB,QAAQ,QAAQ,sBAAsB;;;;;;;;;;EAoJtC,gBACE,8BACA,SAAS,eACR;;;;;;UA0CK;;;;;UA+CA;;;;;;EAkBR,IAAI,YAAY;;;;;;EAahB,kBAAkB;;;;;;;;UAYV;;;;;EAcR,iBAAiB;;;;;;;;;EAYX,WAAW,kBAAkB,SAAS,cAAc,QAAQ;;EAO5D,aAAa,kBAAkB,UAAS,sBAA2B,QAAQ;;;;;;;;EAa3E,iBACJ,kBACA,eACA,SAAS,cACR,QAAQ;;EAOX,YAAY,mBAAmB;;;;;;;;EAWzB,YACJ,QAAQ,YACR,SAAS,aACT,oBAAoB,yBACnB,QAAQ;;;;;;;;;;;EAgEX,OAAO,SAAS,iBAAiB,UAAU,yBAAyB;UAI5D;;;;;;;;;;;;;UAyCA;UA6BA"}
@@ -1,2 +1,2 @@
1
- import{deepFreeze as e}from"../primitives/freeze.js";import"../primitives/version.js";import{PLUGIN_ERROR_CODES as t,PluginError as n}from"../plugin/provider-plugin.js";import{ModelError as r,REGISTRY_ERROR_CODES as i}from"../errors/model-error.js";import{callConfigEquals as a}from"../contract/call-config.js";import{resolveRetryPolicy as o}from"../contract/retry-policy.js";import{createModelCallHandle as s}from"./model-call-handle.js";import{normalizeResolvedModelInfo as c,resolveCallWithModelInfo as l,validateCatalogModels as u,validateModelCatalogSnapshot as d}from"./model-metadata.js";import{streamAdapter as f}from"./model-stream.js";function p(e){if((typeof e!=`object`||!e)&&typeof e!=`function`)return!1;let t;try{t=Reflect.get(e,`then`)}catch{return!0}if(typeof t!=`function`)return!1;try{Promise.resolve(e).catch(()=>{})}catch{}return!0}function m(e){try{return p(e())?TypeError(`plugin cleanup must be synchronous`):void 0}catch(e){return e}}var h=class{adapters=new Map;middleware=[];listeners=new Set;plugins=new Map;maxCatalogModels;maxCatalogBytes;observation;observationResource;constructor(t={}){this.maxCatalogModels=g(t.maxCatalogModels??2048,`maxCatalogModels`),this.maxCatalogBytes=g(t.maxCatalogBytes??4194304,`maxCatalogBytes`),this.observation=t.observation,this.observationResource=e(t.observationResource??{sdkName:`ai-agent-sdk`,sdkVersion:`0.1.3`,runtime:`unknown`})}install(e){let a=typeof e?.id==`string`?e.id:``,o=(e,r,i=[])=>{let o=[...r===void 0?[]:[r],...i],s=o.length<=1?o[0]:AggregateError(o,`plugin ${a} install cleanup failed`);throw new n(e,t.INSTALL_FAILED,a,s===void 0?void 0:{cause:s})};(a.trim().length===0||a!==a.trim())&&o(`plugin id must be a non-empty trimmed string`),this.plugins.has(a)&&o(`plugin "${a}" is already installed`),(typeof e.displayName!=`string`||e.displayName.trim().length===0)&&o(`plugin "${a}" displayName must be non-empty`),typeof e.setup!=`function`&&o(`plugin "${a}" setup must be a function`);let s=e.family??a;(typeof s!=`string`||s.trim().length===0||s!==s.trim())&&o(`plugin "${a}" family must be a non-empty trimmed string`);let c=Object.freeze({pluginId:a,family:s}),l=[],u=[],d=!0,f={registerAdapter:(e,t)=>{if(d||o(`plugin "${a}" staging registrar is closed`),e.length===0)throw new r(`an adapter must register at least one provider route`,i.INVALID_ADAPTER);let n={active:!0,routes:[...e],adapter:t},s=new Set(l.filter(e=>e.active).flatMap(e=>e.routes));for(let t of e)if(s.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);this.prepareRoutes(e,t,new Set,c),l.push(n);let u=(()=>{d&&(n.active=!1)});return u.replace=e=>{if(!d||!n.active)throw new r(`a disposed staged registration cannot replace routes`,i.REGISTRATION_DISPOSED);let a=new Set(l.filter(e=>e.active&&e!==n).flatMap(e=>e.routes));for(let t of e)if(a.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);this.prepareRoutes(e,t,new Set,c),n.routes=[...e]},u},use:e=>{if(d||o(`plugin "${a}" staging registrar is closed`),typeof e!=`function`)throw TypeError(`plugin middleware must be a function`);let t={active:!0,middleware:e};return u.push(t),()=>{d&&(t.active=!1)}}},h;try{let t=e.setup(f);p(t)&&o(`plugin "${a}" setup must be synchronous`),t!==void 0&&typeof t!=`function`&&o(`plugin "${a}" setup must be synchronous and return void or cleanup`),h=typeof t==`function`?t:void 0}catch(e){if(e instanceof n&&e.code===t.INSTALL_FAILED)throw e;o(`plugin "${a}" setup failed`,e)}finally{d=!1}let g=[],_=new Set;try{for(let e of l)if(e.active){for(let t of e.routes){if(_.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);_.add(t)}g.push(...this.prepareRoutes(e.routes,e.adapter,new Set,c))}}catch(e){let t=[];if(h){let e=m(h);e!==void 0&&t.push(e)}o(`plugin "${a}" commit validation failed`,e,t)}let v=u.filter(e=>e.active).map(e=>e.middleware);for(let e of g)this.adapters.set(e.provider.id,e);this.middleware.push(...v);let y={routes:_,registrations:g,middleware:v,...h===void 0?{}:{cleanup:h}};this.plugins.set(a,y),this.emitAdaptersUpdated();let b=!1,x=(()=>{if(b)return;b=!0,this.plugins.delete(a);for(let e of y.registrations)this.adapters.get(e.provider.id)===e&&this.adapters.delete(e.provider.id);for(let e=y.middleware.length-1;e>=0;e--){let t=y.middleware[e],n=t===void 0?-1:this.middleware.lastIndexOf(t);n>=0&&this.middleware.splice(n,1)}this.emitAdaptersUpdated();let e=[];if(y.cleanup){let t=m(y.cleanup);t!==void 0&&e.push(t)}if(e.length>0)throw new n(`plugin "${a}" cleanup failed`,t.CLEANUP_FAILED,a,{cause:AggregateError(e,`plugin "${a}" cleanup failed`)})});return Object.defineProperty(x,"pluginId",{value:a,enumerable:!0}),x}registerAdapter(e,t){if(e.length===0)throw new r(`an adapter must register at least one provider route`,i.INVALID_ADAPTER);let n=new Set,a=!1;this.commitRoutes(n,this.prepareRoutes(e,t,n));let o=(()=>{if(!a){a=!0;for(let e of n)this.adapters.delete(e);n.clear(),this.emitAdaptersUpdated()}});return o.replace=e=>{if(a)throw new r(`a disposed adapter registration cannot replace its routes`,i.REGISTRATION_DISPOSED);this.commitRoutes(n,this.prepareRoutes(e,t,n))},o}prepareRoutes(e,t,n,a){let s=new Set,c=[];for(let l of e){if(typeof l!=`string`||l.length===0)throw new r(`adapter provider route names must be non-empty strings`,i.INVALID_ADAPTER);if(s.has(l)||this.adapters.has(l)&&!n.has(l))throw new r(`an adapter for provider route "${l}" is already registered`,i.DUPLICATE_ADAPTER);let e=t.providerInfo(l);if(typeof e.id!=`string`||e.id!==l||typeof e.name!=`string`||e.name.length===0)throw new r(`adapter metadata for route "${l}" must preserve its id and carry a non-empty name`,i.INVALID_ADAPTER);s.add(l),c.push({adapter:t,provider:{id:e.id,name:e.name},...a===void 0?{}:a,retryPolicy:t.providerRetryPolicy(l)??o(void 0,`provider "${l}" retryPolicy`)})}return c}commitRoutes(e,t){for(let t of e)this.adapters.delete(t);e.clear();for(let n of t)this.adapters.set(n.provider.id,n),e.add(n.provider.id);this.emitAdaptersUpdated()}use(e){return this.middleware.push(e),()=>{let t=this.middleware.indexOf(e);t>=0&&this.middleware.splice(t,1)}}onAdaptersUpdated(e){return this.listeners.add(e),()=>void this.listeners.delete(e)}emitAdaptersUpdated(){for(let e of[...this.listeners])try{e()}catch{}}listProviders(){return[...this.adapters.values()].map(({provider:e})=>({...e}))}async listModels(e,t){let n=await this.registration(e).adapter.listModels(e,t);return u(e,n,this.maxCatalogModels,this.maxCatalogBytes)}async modelCatalog(e,t={}){let n=await this.registration(e).adapter.modelCatalog(e,t);return d(e,n,this.maxCatalogModels,this.maxCatalogBytes)}async resolveModelInfo(e,t,n){let r=this.registration(e),i=await r.adapter.resolveModel(e,t,n);return c(r.provider.id,t,i,this.maxCatalogBytes)}retryPolicy(e){return this.registration(e).retryPolicy}async prepareCall(t,n,o){let s=this.registration(t.provider),u=await s.adapter.prepareCall(t.provider,t.model,n,o),d=c(s.provider.id,t.model,u.model,this.maxCatalogBytes),f=l(t,d),p=e(structuredClone(f.config)),m=f.context===void 0?void 0:e(structuredClone(f.context)),h=e({...t.reasoningEffort===void 0&&p.reasoningEffort!==void 0?{reasoningEffort:!0}:{},...t.maxTokens===void 0&&p.maxTokens!==void 0?{maxTokens:!0}:{}}),g=!1,_=e(structuredClone(d));return Object.freeze({config:p,model:_,retryPolicy:s.retryPolicy,adapterDefaults:h,...m===void 0?{}:{context:m},...d.inputModalities===void 0?{}:{inputModalities:Object.freeze([...d.inputModalities])},stream:(e,t=o)=>{if(g)throw new r(`a prepared call can only be dispatched once`,i.INVALID_PREPARED_CALL);if(!a(e,p))throw new r(`prepared call config changed before adapter dispatch`,i.INVALID_PREPARED_CALL);return g=!0,this.dispatch(e,t,{registration:s,config:p,modelInfo:d,dispatch:(e,t)=>u.stream(e,t)})}})}stream(e,t){return this.dispatch(e,t)}dispatch(e,t,n){let r=`not-sent`,i=n?.registration??this.adapters.get(e.provider);return s({options:e,...i?.family===void 0?{}:{providerFamily:i.family},...i?.pluginId===void 0?{}:{providerPluginId:i.pluginId},...i===void 0?{}:{isRetryable:e=>i.retryPolicy.mode===`always`||i.retryPolicy.retryableCodes.includes(e)},...t===void 0?{}:{context:t},...this.observation===void 0?{}:{defaultObservation:this.observation},resource:this.observationResource,routePresent:n!==void 0||this.adapters.has(e.provider),dispatchState:()=>r,stream:t=>this.dispatchRaw(e,t,()=>{r=`unknown`},n)})}dispatchRaw(e,t,n,r){let i=[...this.middleware],a=()=>{let a=()=>f({options:e,context:t,onDispatch:n,maxCatalogBytes:this.maxCatalogBytes,registration:e=>this.registration(e),registeredAdapter:e=>this.adapters.get(e)?.adapter,...r===void 0?{}:{prepared:r}});for(let n=i.length-1;n>=0;n--){let r=i[n];if(r===void 0)continue;let o=a;a=()=>r(e,o,t)}return a()};return{async*[Symbol.asyncIterator](){yield*a()}}}registration(e){let t=this.adapters.get(e);if(t===void 0)throw new r(`no adapter registered for provider route "${e}"`,i.NO_ADAPTER);return t}};function g(e,t){if(!Number.isSafeInteger(e)||e<1)throw RangeError(`ModelRegistry ${t} must be a positive safe integer`);return e}export{h as ModelRegistry};
1
+ import{deepFreeze as e}from"../primitives/freeze.js";import"../primitives/version.js";import{PLUGIN_ERROR_CODES as t,PluginError as n}from"../plugin/provider-plugin.js";import{ModelError as r,REGISTRY_ERROR_CODES as i}from"../errors/model-error.js";import{callConfigEquals as a}from"../contract/call-config.js";import{resolveRetryPolicy as o}from"../contract/retry-policy.js";import{createModelCallHandle as s}from"./model-call-handle.js";import{normalizeResolvedModelInfo as c,resolveCallWithModelInfo as l,validateCatalogModels as u,validateModelCatalogSnapshot as d}from"./model-metadata.js";import{streamAdapter as f}from"./model-stream.js";function p(e){if((typeof e!=`object`||!e)&&typeof e!=`function`)return!1;let t;try{t=Reflect.get(e,`then`)}catch{return!0}if(typeof t!=`function`)return!1;try{Promise.resolve(e).catch(()=>{})}catch{}return!0}function m(e){try{return p(e())?TypeError(`plugin cleanup must be synchronous`):void 0}catch(e){return e}}var h=class{adapters=new Map;middleware=[];listeners=new Set;plugins=new Map;maxCatalogModels;maxCatalogBytes;observation;observationResource;defaults;constructor(t={}){this.maxCatalogModels=g(t.maxCatalogModels??2048,`maxCatalogModels`),this.maxCatalogBytes=g(t.maxCatalogBytes??4194304,`maxCatalogBytes`),this.observation=t.observation,this.defaults=_(t.defaults??{}),this.observationResource=e(t.observationResource??{sdkName:`ai-agent-sdk`,sdkVersion:`0.1.4`,runtime:`unknown`})}install(e){let a=typeof e?.id==`string`?e.id:``,o=(e,r,i=[])=>{let o=[...r===void 0?[]:[r],...i],s=o.length<=1?o[0]:AggregateError(o,`plugin ${a} install cleanup failed`);throw new n(e,t.INSTALL_FAILED,a,s===void 0?void 0:{cause:s})};(a.trim().length===0||a!==a.trim())&&o(`plugin id must be a non-empty trimmed string`),this.plugins.has(a)&&o(`plugin "${a}" is already installed`),(typeof e.displayName!=`string`||e.displayName.trim().length===0)&&o(`plugin "${a}" displayName must be non-empty`),typeof e.setup!=`function`&&o(`plugin "${a}" setup must be a function`);let s=e.family??a;(typeof s!=`string`||s.trim().length===0||s!==s.trim())&&o(`plugin "${a}" family must be a non-empty trimmed string`);let c=Object.freeze({pluginId:a,family:s}),l=[],u=[],d=!0,f={registerAdapter:(e,t)=>{if(d||o(`plugin "${a}" staging registrar is closed`),e.length===0)throw new r(`an adapter must register at least one provider route`,i.INVALID_ADAPTER);let n={active:!0,routes:[...e],adapter:t},s=new Set(l.filter(e=>e.active).flatMap(e=>e.routes));for(let t of e)if(s.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);this.prepareRoutes(e,t,new Set,c),l.push(n);let u=(()=>{d&&(n.active=!1)});return u.replace=e=>{if(!d||!n.active)throw new r(`a disposed staged registration cannot replace routes`,i.REGISTRATION_DISPOSED);let a=new Set(l.filter(e=>e.active&&e!==n).flatMap(e=>e.routes));for(let t of e)if(a.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);this.prepareRoutes(e,t,new Set,c),n.routes=[...e]},u},use:e=>{if(d||o(`plugin "${a}" staging registrar is closed`),typeof e!=`function`)throw TypeError(`plugin middleware must be a function`);let t={active:!0,middleware:e};return u.push(t),()=>{d&&(t.active=!1)}}},h;try{let t=e.setup(f);p(t)&&o(`plugin "${a}" setup must be synchronous`),t!==void 0&&typeof t!=`function`&&o(`plugin "${a}" setup must be synchronous and return void or cleanup`),h=typeof t==`function`?t:void 0}catch(e){if(e instanceof n&&e.code===t.INSTALL_FAILED)throw e;o(`plugin "${a}" setup failed`,e)}finally{d=!1}let g=[],_=new Set;try{for(let e of l)if(e.active){for(let t of e.routes){if(_.has(t))throw new r(`an adapter for provider route "${t}" is already staged`,i.DUPLICATE_ADAPTER);_.add(t)}g.push(...this.prepareRoutes(e.routes,e.adapter,new Set,c))}}catch(e){let t=[];if(h){let e=m(h);e!==void 0&&t.push(e)}o(`plugin "${a}" commit validation failed`,e,t)}let v=u.filter(e=>e.active).map(e=>e.middleware);for(let e of g)this.adapters.set(e.provider.id,e);this.middleware.push(...v);let y={routes:_,registrations:g,middleware:v,...h===void 0?{}:{cleanup:h}};this.plugins.set(a,y),this.emitAdaptersUpdated();let b=!1,x=(()=>{if(b)return;b=!0,this.plugins.delete(a);for(let e of y.registrations)this.adapters.get(e.provider.id)===e&&this.adapters.delete(e.provider.id);for(let e=y.middleware.length-1;e>=0;e--){let t=y.middleware[e],n=t===void 0?-1:this.middleware.lastIndexOf(t);n>=0&&this.middleware.splice(n,1)}this.emitAdaptersUpdated();let e=[];if(y.cleanup){let t=m(y.cleanup);t!==void 0&&e.push(t)}if(e.length>0)throw new n(`plugin "${a}" cleanup failed`,t.CLEANUP_FAILED,a,{cause:AggregateError(e,`plugin "${a}" cleanup failed`)})});return Object.defineProperty(x,"pluginId",{value:a,enumerable:!0}),x}registerAdapter(e,t){if(e.length===0)throw new r(`an adapter must register at least one provider route`,i.INVALID_ADAPTER);let n=new Set,a=!1;this.commitRoutes(n,this.prepareRoutes(e,t,n));let o=(()=>{if(!a){a=!0;for(let e of n)this.adapters.delete(e);n.clear(),this.emitAdaptersUpdated()}});return o.replace=e=>{if(a)throw new r(`a disposed adapter registration cannot replace its routes`,i.REGISTRATION_DISPOSED);this.commitRoutes(n,this.prepareRoutes(e,t,n))},o}prepareRoutes(e,t,n,a){let s=new Set,c=[];for(let l of e){if(typeof l!=`string`||l.length===0)throw new r(`adapter provider route names must be non-empty strings`,i.INVALID_ADAPTER);if(s.has(l)||this.adapters.has(l)&&!n.has(l))throw new r(`an adapter for provider route "${l}" is already registered`,i.DUPLICATE_ADAPTER);let e=t.providerInfo(l);if(typeof e.id!=`string`||e.id!==l||typeof e.name!=`string`||e.name.length===0)throw new r(`adapter metadata for route "${l}" must preserve its id and carry a non-empty name`,i.INVALID_ADAPTER);s.add(l),c.push({adapter:t,provider:{id:e.id,name:e.name},...a===void 0?{}:a,retryPolicy:t.providerRetryPolicy(l)??o(void 0,`provider "${l}" retryPolicy`)})}return c}commitRoutes(e,t){for(let t of e)this.adapters.delete(t);e.clear();for(let n of t)this.adapters.set(n.provider.id,n),e.add(n.provider.id);this.emitAdaptersUpdated()}use(e){return this.middleware.push(e),()=>{let t=this.middleware.indexOf(e);t>=0&&this.middleware.splice(t,1)}}onAdaptersUpdated(e){return this.listeners.add(e),()=>void this.listeners.delete(e)}emitAdaptersUpdated(){for(let e of[...this.listeners])try{e()}catch{}}listProviders(){return[...this.adapters.values()].map(({provider:e})=>({...e}))}async listModels(e,t){let n=await this.registration(e).adapter.listModels(e,t);return u(e,n,this.maxCatalogModels,this.maxCatalogBytes)}async modelCatalog(e,t={}){let n=await this.registration(e).adapter.modelCatalog(e,t);return d(e,n,this.maxCatalogModels,this.maxCatalogBytes)}async resolveModelInfo(e,t,n){let r=this.registration(e),i=await r.adapter.resolveModel(e,t,n);return c(r.provider.id,t,i,this.maxCatalogBytes,this.defaults)}retryPolicy(e){return this.registration(e).retryPolicy}async prepareCall(t,n,o){let s=this.registration(t.provider),u=await s.adapter.prepareCall(t.provider,t.model,n,o),d=c(s.provider.id,t.model,u.model,this.maxCatalogBytes,this.defaults),f=l(t,d,this.defaults),p=e(structuredClone(f.config)),m=f.context===void 0?void 0:e(structuredClone(f.context)),h=e({...t.maxTokens===void 0&&p.maxTokens!==void 0?{maxTokens:!0}:{}}),g=!1,_=e(structuredClone(d));return Object.freeze({config:p,model:_,retryPolicy:s.retryPolicy,adapterDefaults:h,...m===void 0?{}:{context:m},...f.inputModalities===void 0?{}:{inputModalities:Object.freeze([...f.inputModalities])},stream:(e,t=o)=>{if(g)throw new r(`a prepared call can only be dispatched once`,i.INVALID_PREPARED_CALL);if(!a(e,p))throw new r(`prepared call config changed before adapter dispatch`,i.INVALID_PREPARED_CALL);return g=!0,this.dispatch(e,t,{registration:s,config:p,modelInfo:d,dispatch:(e,t)=>u.stream(e,t)})}})}stream(e,t){return this.dispatch(e,t)}dispatch(e,t,n){let r=`not-sent`,i=n?.registration??this.adapters.get(e.provider);return s({options:e,...i?.family===void 0?{}:{providerFamily:i.family},...i?.pluginId===void 0?{}:{providerPluginId:i.pluginId},...i===void 0?{}:{isRetryable:e=>i.retryPolicy.mode===`always`||i.retryPolicy.retryableCodes.includes(e)},...t===void 0?{}:{context:t},...this.observation===void 0?{}:{defaultObservation:this.observation},resource:this.observationResource,routePresent:n!==void 0||this.adapters.has(e.provider),dispatchState:()=>r,stream:t=>this.dispatchRaw(e,t,()=>{r=`unknown`},n)})}dispatchRaw(e,t,n,r){let i=[...this.middleware],a=()=>{let a=()=>f({options:e,context:t,onDispatch:n,maxCatalogBytes:this.maxCatalogBytes,defaults:this.defaults,registration:e=>this.registration(e),registeredAdapter:e=>this.adapters.get(e)?.adapter,...r===void 0?{}:{prepared:r}});for(let n=i.length-1;n>=0;n--){let r=i[n];if(r===void 0)continue;let o=a;a=()=>r(e,o,t)}return a()};return{async*[Symbol.asyncIterator](){yield*a()}}}registration(e){let t=this.adapters.get(e);if(t===void 0)throw new r(`no adapter registered for provider route "${e}"`,i.NO_ADAPTER);return t}};function g(e,t){if(!Number.isSafeInteger(e)||e<1)throw RangeError(`ModelRegistry ${t} must be a positive safe integer`);return e}function _(t){if(t.contextWindow!==void 0&&g(t.contextWindow,`defaults.contextWindow`),t.maxTokens!==void 0&&g(t.maxTokens,`defaults.maxTokens`),t.inputModalities!==void 0&&(t.inputModalities.length===0||new Set(t.inputModalities).size!==t.inputModalities.length))throw RangeError(`ModelRegistry defaults.inputModalities must be non-empty and unique`);return e({...t.contextWindow===void 0?{}:{contextWindow:t.contextWindow},...t.maxTokens===void 0?{}:{maxTokens:t.maxTokens},...t.inputModalities===void 0?{}:{inputModalities:[...t.inputModalities]}})}export{h as ModelRegistry};
2
2
  //# sourceMappingURL=registry.js.map