@fleetagent/pi-ai 0.1.9 → 0.2.1

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 (148) hide show
  1. package/dist/cli.d.ts.map +1 -1
  2. package/dist/cli.js +29 -24
  3. package/dist/cli.js.map +1 -1
  4. package/dist/env-api-keys.d.ts.map +1 -1
  5. package/dist/env-api-keys.js +1 -1
  6. package/dist/env-api-keys.js.map +1 -1
  7. package/dist/image-models.generated.d.ts +180 -0
  8. package/dist/image-models.generated.d.ts.map +1 -1
  9. package/dist/image-models.generated.js +184 -4
  10. package/dist/image-models.generated.js.map +1 -1
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/models.d.ts +3 -3
  15. package/dist/models.d.ts.map +1 -1
  16. package/dist/models.generated.d.ts +5389 -2066
  17. package/dist/models.generated.d.ts.map +1 -1
  18. package/dist/models.generated.js +5402 -2301
  19. package/dist/models.generated.js.map +1 -1
  20. package/dist/models.js +60 -45
  21. package/dist/models.js.map +1 -1
  22. package/dist/oauth.d.ts +6 -1
  23. package/dist/oauth.d.ts.map +1 -1
  24. package/dist/oauth.js +4 -1
  25. package/dist/oauth.js.map +1 -1
  26. package/dist/providers/amazon-bedrock.d.ts +5 -4
  27. package/dist/providers/amazon-bedrock.d.ts.map +1 -1
  28. package/dist/providers/amazon-bedrock.js +303 -330
  29. package/dist/providers/amazon-bedrock.js.map +1 -1
  30. package/dist/providers/anthropic.d.ts +5 -4
  31. package/dist/providers/anthropic.d.ts.map +1 -1
  32. package/dist/providers/anthropic.js +492 -499
  33. package/dist/providers/anthropic.js.map +1 -1
  34. package/dist/providers/azure-openai-responses.d.ts +4 -2
  35. package/dist/providers/azure-openai-responses.d.ts.map +1 -1
  36. package/dist/providers/azure-openai-responses.js +52 -35
  37. package/dist/providers/azure-openai-responses.js.map +1 -1
  38. package/dist/providers/faux.d.ts +19 -22
  39. package/dist/providers/faux.d.ts.map +1 -1
  40. package/dist/providers/faux.js +106 -70
  41. package/dist/providers/faux.js.map +1 -1
  42. package/dist/providers/github-copilot-headers.d.ts +7 -4
  43. package/dist/providers/github-copilot-headers.d.ts.map +1 -1
  44. package/dist/providers/github-copilot-headers.js.map +1 -1
  45. package/dist/providers/google-shared.d.ts +24 -5
  46. package/dist/providers/google-shared.d.ts.map +1 -1
  47. package/dist/providers/google-shared.js +139 -140
  48. package/dist/providers/google-shared.js.map +1 -1
  49. package/dist/providers/google-vertex.d.ts +3 -7
  50. package/dist/providers/google-vertex.d.ts.map +1 -1
  51. package/dist/providers/google-vertex.js +216 -219
  52. package/dist/providers/google-vertex.js.map +1 -1
  53. package/dist/providers/google.d.ts +4 -7
  54. package/dist/providers/google.d.ts.map +1 -1
  55. package/dist/providers/google.js +214 -218
  56. package/dist/providers/google.js.map +1 -1
  57. package/dist/providers/images/openrouter.d.ts.map +1 -1
  58. package/dist/providers/images/openrouter.js +37 -27
  59. package/dist/providers/images/openrouter.js.map +1 -1
  60. package/dist/providers/mistral.d.ts +7 -6
  61. package/dist/providers/mistral.d.ts.map +1 -1
  62. package/dist/providers/mistral.js +287 -265
  63. package/dist/providers/mistral.js.map +1 -1
  64. package/dist/providers/openai-codex-responses.d.ts +8 -5
  65. package/dist/providers/openai-codex-responses.d.ts.map +1 -1
  66. package/dist/providers/openai-codex-responses.js +493 -391
  67. package/dist/providers/openai-codex-responses.js.map +1 -1
  68. package/dist/providers/openai-completions.d.ts +7 -10
  69. package/dist/providers/openai-completions.d.ts.map +1 -1
  70. package/dist/providers/openai-completions.js +670 -664
  71. package/dist/providers/openai-completions.js.map +1 -1
  72. package/dist/providers/openai-responses-shared.d.ts +5 -4
  73. package/dist/providers/openai-responses-shared.d.ts.map +1 -1
  74. package/dist/providers/openai-responses-shared.js +390 -360
  75. package/dist/providers/openai-responses-shared.js.map +1 -1
  76. package/dist/providers/openai-responses.d.ts +5 -5
  77. package/dist/providers/openai-responses.d.ts.map +1 -1
  78. package/dist/providers/openai-responses.js +134 -109
  79. package/dist/providers/openai-responses.js.map +1 -1
  80. package/dist/providers/simple-options.d.ts +4 -2
  81. package/dist/providers/simple-options.d.ts.map +1 -1
  82. package/dist/providers/simple-options.js.map +1 -1
  83. package/dist/providers/transform-messages.d.ts.map +1 -1
  84. package/dist/providers/transform-messages.js +112 -137
  85. package/dist/providers/transform-messages.js.map +1 -1
  86. package/dist/stream.d.ts +0 -1
  87. package/dist/stream.d.ts.map +1 -1
  88. package/dist/stream.js +0 -1
  89. package/dist/stream.js.map +1 -1
  90. package/dist/types.d.ts +91 -63
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/types.js.map +1 -1
  93. package/dist/utils/error-body.d.ts.map +1 -1
  94. package/dist/utils/error-body.js +15 -4
  95. package/dist/utils/error-body.js.map +1 -1
  96. package/dist/utils/estimate.d.ts +4 -0
  97. package/dist/utils/estimate.d.ts.map +1 -1
  98. package/dist/utils/estimate.js +3 -1
  99. package/dist/utils/estimate.js.map +1 -1
  100. package/dist/utils/headers.d.ts +3 -0
  101. package/dist/utils/headers.d.ts.map +1 -1
  102. package/dist/utils/headers.js +21 -0
  103. package/dist/utils/headers.js.map +1 -1
  104. package/dist/utils/json-parse.d.ts.map +1 -1
  105. package/dist/utils/json-parse.js +17 -19
  106. package/dist/utils/json-parse.js.map +1 -1
  107. package/dist/utils/oauth/anthropic.d.ts +4 -11
  108. package/dist/utils/oauth/anthropic.d.ts.map +1 -1
  109. package/dist/utils/oauth/anthropic.js +100 -117
  110. package/dist/utils/oauth/anthropic.js.map +1 -1
  111. package/dist/utils/oauth/device-code.d.ts.map +1 -1
  112. package/dist/utils/oauth/device-code.js +51 -38
  113. package/dist/utils/oauth/device-code.js.map +1 -1
  114. package/dist/utils/oauth/github-copilot.d.ts +6 -9
  115. package/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  116. package/dist/utils/oauth/github-copilot.js +47 -42
  117. package/dist/utils/oauth/github-copilot.js.map +1 -1
  118. package/dist/utils/oauth/index.d.ts +8 -17
  119. package/dist/utils/oauth/index.d.ts.map +1 -1
  120. package/dist/utils/oauth/index.js +27 -23
  121. package/dist/utils/oauth/index.js.map +1 -1
  122. package/dist/utils/oauth/oauth-page.d.ts.map +1 -1
  123. package/dist/utils/oauth/oauth-page.js.map +1 -1
  124. package/dist/utils/oauth/openai-codex.d.ts +7 -12
  125. package/dist/utils/oauth/openai-codex.d.ts.map +1 -1
  126. package/dist/utils/oauth/openai-codex.js +72 -89
  127. package/dist/utils/oauth/openai-codex.js.map +1 -1
  128. package/dist/utils/oauth/pkce.d.ts +5 -4
  129. package/dist/utils/oauth/pkce.d.ts.map +1 -1
  130. package/dist/utils/oauth/pkce.js.map +1 -1
  131. package/dist/utils/oauth/types.d.ts +7 -2
  132. package/dist/utils/oauth/types.d.ts.map +1 -1
  133. package/dist/utils/oauth/types.js.map +1 -1
  134. package/dist/utils/provider-retry.d.ts +16 -0
  135. package/dist/utils/provider-retry.d.ts.map +1 -0
  136. package/dist/utils/provider-retry.js +94 -0
  137. package/dist/utils/provider-retry.js.map +1 -0
  138. package/dist/utils/retry.d.ts +14 -0
  139. package/dist/utils/retry.d.ts.map +1 -1
  140. package/dist/utils/retry.js +84 -0
  141. package/dist/utils/retry.js.map +1 -1
  142. package/dist/utils/typebox-helpers.d.ts +5 -4
  143. package/dist/utils/typebox-helpers.d.ts.map +1 -1
  144. package/dist/utils/typebox-helpers.js.map +1 -1
  145. package/dist/utils/validation.d.ts.map +1 -1
  146. package/dist/utils/validation.js +102 -99
  147. package/dist/utils/validation.js.map +1 -1
  148. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAC5G,YAAY,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACzF,cAAc,qBAAqB,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,cAAc,yCAAyC,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EACX,2BAA2B,EAC3B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAClF,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,YAAY,EACX,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GACjB,MAAM,wBAAwB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export type { Static, TSchema } from \"typebox\";\nexport { Type } from \"typebox\";\n\nexport * from \"./api-registry.ts\";\nexport * from \"./env-api-keys.ts\";\nexport * from \"./image-models.ts\";\nexport * from \"./images.ts\";\nexport * from \"./images-api-registry.ts\";\nexport * from \"./models.ts\";\nexport type { BedrockOptions, BedrockThinkingDisplay } from \"./providers/amazon-bedrock.ts\";\nexport type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from \"./providers/anthropic.ts\";\nexport type { AzureOpenAIResponsesOptions } from \"./providers/azure-openai-responses.ts\";\nexport * from \"./providers/faux.ts\";\nexport type { GoogleOptions } from \"./providers/google.ts\";\nexport type { GoogleThinkingLevel } from \"./providers/google-shared.ts\";\nexport type { GoogleVertexOptions } from \"./providers/google-vertex.ts\";\nexport * from \"./providers/images/register-builtins.ts\";\nexport type { MistralOptions } from \"./providers/mistral.ts\";\nexport type {\n\tOpenAICodexResponsesOptions,\n\tOpenAICodexWebSocketDebugStats,\n} from \"./providers/openai-codex-responses.ts\";\nexport type { OpenAICompletionsOptions } from \"./providers/openai-completions.ts\";\nexport type { OpenAIResponsesOptions } from \"./providers/openai-responses.ts\";\nexport * from \"./providers/register-builtins.ts\";\nexport * from \"./session-resources.ts\";\nexport * from \"./stream.ts\";\nexport * from \"./types.ts\";\nexport * from \"./utils/diagnostics.ts\";\nexport * from \"./utils/event-stream.ts\";\nexport * from \"./utils/json-parse.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\nexport * from \"./utils/overflow.ts\";\nexport * from \"./utils/retry.ts\";\nexport * from \"./utils/typebox-helpers.ts\";\nexport * from \"./utils/validation.ts\";\n"]}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAC5B,YAAY,EAAE,cAAc,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAC5F,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAC5G,YAAY,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAC;AACzF,cAAc,qBAAqB,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,cAAc,yCAAyC,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EACX,2BAA2B,EAC3B,8BAA8B,GAC9B,MAAM,uCAAuC,CAAC;AAC/C,YAAY,EAAE,wBAAwB,EAAE,MAAM,mCAAmC,CAAC;AAClF,YAAY,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAC9E,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,YAAY,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AACpF,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AACtC,YAAY,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACtD,YAAY,EACX,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,WAAW,EACX,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,GACjB,MAAM,wBAAwB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export type { Static, TSchema } from \"typebox\";\nexport { Type } from \"typebox\";\n\nexport * from \"./api-registry.ts\";\nexport * from \"./env-api-keys.ts\";\nexport * from \"./image-models.ts\";\nexport * from \"./images.ts\";\nexport * from \"./images-api-registry.ts\";\nexport * from \"./models.ts\";\nexport type { BedrockOptions, BedrockThinkingDisplay } from \"./providers/amazon-bedrock.ts\";\nexport type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from \"./providers/anthropic.ts\";\nexport type { AzureOpenAIResponsesOptions } from \"./providers/azure-openai-responses.ts\";\nexport * from \"./providers/faux.ts\";\nexport type { GoogleOptions } from \"./providers/google.ts\";\nexport type { GoogleThinkingLevel } from \"./providers/google-shared.ts\";\nexport type { GoogleVertexOptions } from \"./providers/google-vertex.ts\";\nexport * from \"./providers/images/register-builtins.ts\";\nexport type { MistralOptions } from \"./providers/mistral.ts\";\nexport type {\n\tOpenAICodexResponsesOptions,\n\tOpenAICodexWebSocketDebugStats,\n} from \"./providers/openai-codex-responses.ts\";\nexport type { OpenAICompletionsOptions } from \"./providers/openai-completions.ts\";\nexport type { OpenAIResponsesOptions } from \"./providers/openai-responses.ts\";\nexport * from \"./providers/register-builtins.ts\";\nexport * from \"./session-resources.ts\";\nexport * from \"./stream.ts\";\nexport * from \"./types.ts\";\nexport * from \"./utils/diagnostics.ts\";\nexport type { AssistantUsageInfo, ContextUsageEstimate } from \"./utils/estimate.ts\";\nexport * from \"./utils/event-stream.ts\";\nexport * from \"./utils/json-parse.ts\";\nexport type { PKCEPair } from \"./utils/oauth/pkce.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\nexport * from \"./utils/overflow.ts\";\nexport * from \"./utils/retry.ts\";\nexport * from \"./utils/typebox-helpers.ts\";\nexport * from \"./utils/validation.ts\";\n"]}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAI5B,cAAc,qBAAqB,CAAC;AAIpC,cAAc,yCAAyC,CAAC;AAQxD,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AActC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export type { Static, TSchema } from \"typebox\";\nexport { Type } from \"typebox\";\n\nexport * from \"./api-registry.ts\";\nexport * from \"./env-api-keys.ts\";\nexport * from \"./image-models.ts\";\nexport * from \"./images.ts\";\nexport * from \"./images-api-registry.ts\";\nexport * from \"./models.ts\";\nexport type { BedrockOptions, BedrockThinkingDisplay } from \"./providers/amazon-bedrock.ts\";\nexport type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from \"./providers/anthropic.ts\";\nexport type { AzureOpenAIResponsesOptions } from \"./providers/azure-openai-responses.ts\";\nexport * from \"./providers/faux.ts\";\nexport type { GoogleOptions } from \"./providers/google.ts\";\nexport type { GoogleThinkingLevel } from \"./providers/google-shared.ts\";\nexport type { GoogleVertexOptions } from \"./providers/google-vertex.ts\";\nexport * from \"./providers/images/register-builtins.ts\";\nexport type { MistralOptions } from \"./providers/mistral.ts\";\nexport type {\n\tOpenAICodexResponsesOptions,\n\tOpenAICodexWebSocketDebugStats,\n} from \"./providers/openai-codex-responses.ts\";\nexport type { OpenAICompletionsOptions } from \"./providers/openai-completions.ts\";\nexport type { OpenAIResponsesOptions } from \"./providers/openai-responses.ts\";\nexport * from \"./providers/register-builtins.ts\";\nexport * from \"./session-resources.ts\";\nexport * from \"./stream.ts\";\nexport * from \"./types.ts\";\nexport * from \"./utils/diagnostics.ts\";\nexport * from \"./utils/event-stream.ts\";\nexport * from \"./utils/json-parse.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\nexport * from \"./utils/overflow.ts\";\nexport * from \"./utils/retry.ts\";\nexport * from \"./utils/typebox-helpers.ts\";\nexport * from \"./utils/validation.ts\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,0BAA0B,CAAC;AACzC,cAAc,aAAa,CAAC;AAI5B,cAAc,qBAAqB,CAAC;AAIpC,cAAc,yCAAyC,CAAC;AAQxD,cAAc,kCAAkC,CAAC;AACjD,cAAc,wBAAwB,CAAC;AACvC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,wBAAwB,CAAC;AAEvC,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAetC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC","sourcesContent":["export type { Static, TSchema } from \"typebox\";\nexport { Type } from \"typebox\";\n\nexport * from \"./api-registry.ts\";\nexport * from \"./env-api-keys.ts\";\nexport * from \"./image-models.ts\";\nexport * from \"./images.ts\";\nexport * from \"./images-api-registry.ts\";\nexport * from \"./models.ts\";\nexport type { BedrockOptions, BedrockThinkingDisplay } from \"./providers/amazon-bedrock.ts\";\nexport type { AnthropicEffort, AnthropicOptions, AnthropicThinkingDisplay } from \"./providers/anthropic.ts\";\nexport type { AzureOpenAIResponsesOptions } from \"./providers/azure-openai-responses.ts\";\nexport * from \"./providers/faux.ts\";\nexport type { GoogleOptions } from \"./providers/google.ts\";\nexport type { GoogleThinkingLevel } from \"./providers/google-shared.ts\";\nexport type { GoogleVertexOptions } from \"./providers/google-vertex.ts\";\nexport * from \"./providers/images/register-builtins.ts\";\nexport type { MistralOptions } from \"./providers/mistral.ts\";\nexport type {\n\tOpenAICodexResponsesOptions,\n\tOpenAICodexWebSocketDebugStats,\n} from \"./providers/openai-codex-responses.ts\";\nexport type { OpenAICompletionsOptions } from \"./providers/openai-completions.ts\";\nexport type { OpenAIResponsesOptions } from \"./providers/openai-responses.ts\";\nexport * from \"./providers/register-builtins.ts\";\nexport * from \"./session-resources.ts\";\nexport * from \"./stream.ts\";\nexport * from \"./types.ts\";\nexport * from \"./utils/diagnostics.ts\";\nexport type { AssistantUsageInfo, ContextUsageEstimate } from \"./utils/estimate.ts\";\nexport * from \"./utils/event-stream.ts\";\nexport * from \"./utils/json-parse.ts\";\nexport type { PKCEPair } from \"./utils/oauth/pkce.ts\";\nexport type {\n\tOAuthAuthInfo,\n\tOAuthCredentials,\n\tOAuthDeviceCodeInfo,\n\tOAuthLoginCallbacks,\n\tOAuthPrompt,\n\tOAuthProvider,\n\tOAuthProviderId,\n\tOAuthProviderInfo,\n\tOAuthProviderInterface,\n\tOAuthSelectOption,\n\tOAuthSelectPrompt,\n} from \"./utils/oauth/types.ts\";\nexport * from \"./utils/overflow.ts\";\nexport * from \"./utils/retry.ts\";\nexport * from \"./utils/typebox-helpers.ts\";\nexport * from \"./utils/validation.ts\";\n"]}
package/dist/models.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { MODELS } from "./models.generated.ts";
2
- import type { Api, KnownProvider, Model, ModelThinkingLevel, Usage } from "./types.ts";
2
+ import type { Api, KnownProvider, Model, ModelThinkingLevel, Usage, UsageCost } from "./types.ts";
3
3
  export interface ModelCatalogRefreshOptions {
4
4
  /** URL of the upstream models/v1/index.json catalog index. Defaults to PI_MODEL_CATALOG_URL. */
5
5
  indexUrl?: string;
@@ -32,7 +32,7 @@ export declare function loadCachedModelCatalog(options?: Pick<ModelCatalogRefres
32
32
  export declare function resetModelCatalog(): void;
33
33
  /**
34
34
  * Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.
35
- * The upstream format matches the catalog published by earendil-works/pi's publish-model-catalog workflow.
35
+ * The upstream format matches the catalog produced by the publish-model-catalog workflow.
36
36
  */
37
37
  export declare function refreshModelCatalog(options?: ModelCatalogRefreshOptions): Promise<ModelCatalogRefreshResult>;
38
38
  type ModelApi<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]> = (typeof MODELS)[TProvider][TModelId] extends {
@@ -41,7 +41,7 @@ type ModelApi<TProvider extends KnownProvider, TModelId extends keyof (typeof MO
41
41
  export declare function getModel<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(provider: TProvider, modelId: TModelId): Model<ModelApi<TProvider, TModelId>>;
42
42
  export declare function getProviders(): KnownProvider[];
43
43
  export declare function getModels<TProvider extends KnownProvider>(provider: TProvider): Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[];
44
- export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage["cost"];
44
+ export declare function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): UsageCost;
45
45
  export declare function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[];
46
46
  export declare function clampThinkingLevel<TApi extends Api>(model: Model<TApi>, level: ModelThinkingLevel): ModelThinkingLevel;
47
47
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { MODELS } from \"./models.generated.ts\";\nimport type { Api, KnownProvider, Model, ModelThinkingLevel, Usage } from \"./types.ts\";\n\nconst MODEL_CATALOG_SCHEMA_VERSION = 1;\n\ninterface ModelCatalogIndexEntry {\n\tminimumPiVersion: string;\n\trevision: string;\n}\n\ninterface ModelCatalogIndex {\n\tschemaVersion: number;\n\tdefaultRevision?: string;\n\tcatalogs?: ModelCatalogIndexEntry[];\n}\n\ninterface CachedModelCatalog {\n\tschemaVersion: number;\n\tindexUrl: string;\n\trevision: string;\n\tfetchedAt: number;\n\tetag?: string;\n\tlastModified?: string;\n\tmodels: Record<string, Record<string, Model<Api>>>;\n}\n\nexport interface ModelCatalogRefreshOptions {\n\t/** URL of the upstream models/v1/index.json catalog index. Defaults to PI_MODEL_CATALOG_URL. */\n\tindexUrl?: string;\n\t/** Persistent cache file. Defaults to PI_MODEL_CATALOG_CACHE_PATH or ~/.cache/pi/model-catalog.json. */\n\tcachePath?: string;\n\t/** Reuse cache without a network request while it is this fresh. Default: 6 hours. */\n\tttlMs?: number;\n\t/** Ignore TTL and conditional validators. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n\t/** Test hook. Defaults to global fetch. */\n\tfetch?: typeof fetch;\n\t/** Test hook. Defaults to Date.now(). */\n\tnow?: () => number;\n}\n\nexport interface ModelCatalogRefreshResult {\n\tloaded: boolean;\n\tupdated: boolean;\n\tfromCache: boolean;\n\trevision?: string;\n\tproviderCount: number;\n\tmodelCount: number;\n}\ntype NodeFs = {\n\texistsSync(path: string): boolean;\n\tmkdirSync(path: string, options: { recursive: boolean }): void;\n\treadFileSync(path: string, encoding: BufferEncoding): string;\n\twriteFileSync(path: string, content: string): void;\n};\n\ntype NodeOs = { homedir(): string };\n\ntype NodePath = {\n\tdirname(path: string): string;\n\tjoin(...parts: string[]): string;\n};\n\nfunction getNodeBuiltin<T>(name: string): T | undefined {\n\treturn typeof process === \"undefined\" ? undefined : (process.getBuiltinModule?.(name) as T | undefined);\n}\n\nfunction getNodeModelCatalogCachePath(): string | undefined {\n\tconst os = getNodeBuiltin<NodeOs>(\"os\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!os || !path) return undefined;\n\treturn path.join(os.homedir(), \".cache\", \"pi\", \"model-catalog.json\");\n}\n\nconst modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFinitePositiveNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction isModel(value: unknown, provider: string, id: string): value is Model<Api> {\n\tif (!isRecord(value)) return false;\n\tif (value.id !== id || value.provider !== provider) return false;\n\tif (typeof value.name !== \"string\" || value.name.length === 0) return false;\n\tif (typeof value.api !== \"string\" || value.api.length === 0) return false;\n\tif (typeof value.baseUrl !== \"string\" || value.baseUrl.length === 0) return false;\n\tif (typeof value.reasoning !== \"boolean\") return false;\n\tif (!Array.isArray(value.input) || value.input.some((entry) => entry !== \"text\" && entry !== \"image\")) return false;\n\tif (!isRecord(value.cost)) return false;\n\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\tif (typeof value.cost[field] !== \"number\" || !Number.isFinite(value.cost[field])) return false;\n\t}\n\treturn isFinitePositiveNumber(value.contextWindow) && isFinitePositiveNumber(value.maxTokens);\n}\n\nfunction validateCatalogModels(value: unknown): Record<string, Record<string, Model<Api>>> {\n\tif (!isRecord(value)) throw new Error(\"Model catalog must contain an object\");\n\tconst providers: Record<string, Record<string, Model<Api>>> = {};\n\tfor (const [provider, providerModels] of Object.entries(value)) {\n\t\tif (!isRecord(providerModels)) throw new Error(`Model catalog provider must contain an object: ${provider}`);\n\t\tconst models: Record<string, Model<Api>> = {};\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tif (!isModel(model, provider, id)) throw new Error(`Invalid model catalog entry: ${provider}/${id}`);\n\t\t\tmodels[id] = model;\n\t\t}\n\t\tproviders[provider] = models;\n\t}\n\treturn providers;\n}\n\nfunction countCatalogModels(models: Record<string, Record<string, Model<Api>>>): {\n\tproviderCount: number;\n\tmodelCount: number;\n} {\n\tlet modelCount = 0;\n\tfor (const providerModels of Object.values(models)) modelCount += Object.keys(providerModels).length;\n\treturn { providerCount: Object.keys(models).length, modelCount };\n}\n\nfunction applyCatalogModels(models: Record<string, Record<string, Model<Api>>>): void {\n\tfor (const [provider, providerModels] of Object.entries(models)) {\n\t\tconst registryProviderModels = modelRegistry.get(provider) ?? new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tregistryProviderModels.set(id, model);\n\t\t}\n\t\tmodelRegistry.set(provider, registryProviderModels);\n\t}\n}\n\nfunction readCachedCatalog(cachePath: string | undefined, indexUrl?: string): CachedModelCatalog | undefined {\n\ttry {\n\t\tif (!cachePath) return undefined;\n\t\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\t\tif (!fs?.existsSync(cachePath)) return undefined;\n\t\tconst parsed = JSON.parse(fs.readFileSync(cachePath, \"utf8\")) as unknown;\n\t\tif (!isRecord(parsed)) return undefined;\n\t\tif (parsed.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) return undefined;\n\t\tif (typeof parsed.indexUrl !== \"string\" || typeof parsed.revision !== \"string\") return undefined;\n\t\tif (indexUrl !== undefined && parsed.indexUrl !== indexUrl) return undefined;\n\t\tif (typeof parsed.fetchedAt !== \"number\" || !Number.isFinite(parsed.fetchedAt)) return undefined;\n\t\tconst cached: CachedModelCatalog = {\n\t\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\t\tindexUrl: parsed.indexUrl,\n\t\t\trevision: parsed.revision,\n\t\t\tfetchedAt: parsed.fetchedAt,\n\t\t\tmodels: validateCatalogModels(parsed.models),\n\t\t};\n\t\tif (typeof parsed.etag === \"string\") cached.etag = parsed.etag;\n\t\tif (typeof parsed.lastModified === \"string\") cached.lastModified = parsed.lastModified;\n\t\treturn cached;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeCachedCatalog(cachePath: string | undefined, catalog: CachedModelCatalog): void {\n\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!cachePath || !fs || !path) return;\n\tfs.mkdirSync(path.dirname(cachePath), { recursive: true });\n\tfs.writeFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\\n`);\n}\n\nfunction getCachePath(options?: Pick<ModelCatalogRefreshOptions, \"cachePath\">): string | undefined {\n\tconst envPath = typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_CACHE_PATH;\n\treturn options?.cachePath ?? envPath ?? getNodeModelCatalogCachePath();\n}\n\nfunction getIndexUrl(options?: Pick<ModelCatalogRefreshOptions, \"indexUrl\">): string | undefined {\n\treturn options?.indexUrl ?? (typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_URL);\n}\n\nfunction resolveCatalogUrl(indexUrl: string, revision: string): string {\n\treturn new URL(`revisions/${encodeURIComponent(revision)}/models.json`, indexUrl).toString();\n}\n\nfunction selectRevision(index: ModelCatalogIndex): string | undefined {\n\treturn index.defaultRevision ?? index.catalogs?.at(-1)?.revision;\n}\n\nfunction createResult(\n\tmodels: Record<string, Record<string, Model<Api>>> | undefined,\n\tresult: Pick<ModelCatalogRefreshResult, \"loaded\" | \"updated\" | \"fromCache\" | \"revision\">,\n): ModelCatalogRefreshResult {\n\tconst counts = models ? countCatalogModels(models) : { providerCount: 0, modelCount: 0 };\n\treturn { ...result, ...counts };\n}\n\nfunction initializeStaticRegistry(): void {\n\tmodelRegistry.clear();\n\tfor (const [provider, models] of Object.entries(MODELS)) {\n\t\tconst providerModels = new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(models)) {\n\t\t\tproviderModels.set(id, model as Model<Api>);\n\t\t}\n\t\tmodelRegistry.set(provider, providerModels);\n\t}\n}\n\ninitializeStaticRegistry();\n\n/**\n * Load a previously refreshed model catalog from disk and overlay it on the generated catalog.\n * This is synchronous so callers can update built-in model lists before constructing registries.\n */\nexport function loadCachedModelCatalog(\n\toptions: Pick<ModelCatalogRefreshOptions, \"cachePath\" | \"indexUrl\"> = {},\n): ModelCatalogRefreshResult {\n\tconst cached = readCachedCatalog(getCachePath(options), getIndexUrl(options));\n\tif (!cached) return createResult(undefined, { loaded: false, updated: false, fromCache: true });\n\tapplyCatalogModels(cached.models);\n\treturn createResult(cached.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: cached.revision,\n\t});\n}\n\n/** Reset runtime overlays. Intended for tests. */\nexport function resetModelCatalog(): void {\n\tinitializeStaticRegistry();\n}\n\n/**\n * Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.\n * The upstream format matches the catalog published by earendil-works/pi's publish-model-catalog workflow.\n */\nexport async function refreshModelCatalog(\n\toptions: ModelCatalogRefreshOptions = {},\n): Promise<ModelCatalogRefreshResult> {\n\tconst indexUrl = getIndexUrl(options);\n\tif (!indexUrl) return createResult(undefined, { loaded: false, updated: false, fromCache: false });\n\tconst cachePath = getCachePath(options);\n\tconst cached = readCachedCatalog(cachePath, indexUrl);\n\tconst now = options.now?.() ?? Date.now();\n\tconst ttlMs = options.ttlMs ?? 6 * 60 * 60 * 1000;\n\tif (!options.force && cached && now - cached.fetchedAt < ttlMs) {\n\t\tapplyCatalogModels(cached.models);\n\t\treturn createResult(cached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: cached.revision,\n\t\t});\n\t}\n\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst headers: Record<string, string> = {};\n\tif (!options.force && cached?.etag) headers[\"If-None-Match\"] = cached.etag;\n\tif (!options.force && cached?.lastModified) headers[\"If-Modified-Since\"] = cached.lastModified;\n\tconst indexResponse = await fetchImpl(indexUrl, { headers, signal: options.signal });\n\tif (indexResponse.status === 304 && cached) {\n\t\tconst nextCached = { ...cached, fetchedAt: now };\n\t\twriteCachedCatalog(cachePath, nextCached);\n\t\tapplyCatalogModels(nextCached.models);\n\t\treturn createResult(nextCached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: nextCached.revision,\n\t\t});\n\t}\n\tif (!indexResponse.ok) throw new Error(`Model catalog index request failed: ${indexResponse.status}`);\n\tconst index = (await indexResponse.json()) as ModelCatalogIndex;\n\tif (!isRecord(index) || index.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {\n\t\tthrow new Error(\"Unsupported model catalog index schema\");\n\t}\n\tconst revision = selectRevision(index);\n\tif (!revision) throw new Error(\"Model catalog index does not contain a revision\");\n\tif (!options.force && cached?.revision === revision) {\n\t\tconst nextCached = { ...cached, fetchedAt: now };\n\t\twriteCachedCatalog(cachePath, nextCached);\n\t\tapplyCatalogModels(nextCached.models);\n\t\treturn createResult(nextCached.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision,\n\t\t});\n\t}\n\n\tconst catalogResponse = await fetchImpl(resolveCatalogUrl(indexUrl, revision), { signal: options.signal });\n\tif (!catalogResponse.ok) throw new Error(`Model catalog request failed: ${catalogResponse.status}`);\n\tconst models = validateCatalogModels(await catalogResponse.json());\n\tconst nextCached: CachedModelCatalog = {\n\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\tindexUrl,\n\t\trevision,\n\t\tfetchedAt: now,\n\t\tmodels,\n\t};\n\tconst etag = indexResponse.headers.get(\"etag\");\n\tif (etag) nextCached.etag = etag;\n\tconst lastModified = indexResponse.headers.get(\"last-modified\");\n\tif (lastModified) nextCached.lastModified = lastModified;\n\twriteCachedCatalog(cachePath, nextCached);\n\tapplyCatalogModels(models);\n\treturn createResult(models, { loaded: true, updated: true, fromCache: false, revision });\n}\n\ntype ModelApi<\n\tTProvider extends KnownProvider,\n\tTModelId extends keyof (typeof MODELS)[TProvider],\n> = (typeof MODELS)[TProvider][TModelId] extends { api: infer TApi } ? (TApi extends Api ? TApi : never) : never;\n\nexport function getModel<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(\n\tprovider: TProvider,\n\tmodelId: TModelId,\n): Model<ModelApi<TProvider, TModelId>> {\n\tconst providerModels = modelRegistry.get(provider);\n\treturn providerModels?.get(modelId as string) as Model<ModelApi<TProvider, TModelId>>;\n}\n\nexport function getProviders(): KnownProvider[] {\n\treturn Array.from(modelRegistry.keys()) as KnownProvider[];\n}\n\nexport function getModels<TProvider extends KnownProvider>(\n\tprovider: TProvider,\n): Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[] {\n\tconst models = modelRegistry.get(provider);\n\treturn models ? (Array.from(models.values()) as Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[]) : [];\n}\n\nexport function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): Usage[\"cost\"] {\n\tusage.cost.input = (model.cost.input / 1000000) * usage.input;\n\tusage.cost.output = (model.cost.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (model.cost.cacheWrite / 1000000) * usage.cacheWrite;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tif (availableLevels.includes(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevels.includes(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual<TApi extends Api>(\n\ta: Model<TApi> | null | undefined,\n\tb: Model<TApi> | null | undefined,\n): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider === b.provider;\n}\n"]}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"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","sourcesContent":["import { MODELS } from \"./models.generated.ts\";\nimport type { Api, KnownProvider, Model, ModelThinkingLevel, Usage, UsageCost } from \"./types.ts\";\n\nconst MODEL_CATALOG_SCHEMA_VERSION = 1;\n\ninterface ModelCatalogIndexEntry {\n\tminimumPiVersion: string;\n\trevision: string;\n}\n\ninterface ModelCatalogIndex {\n\tschemaVersion: number;\n\tdefaultRevision?: string;\n\tcatalogs?: ModelCatalogIndexEntry[];\n}\n\ninterface CachedModelCatalog {\n\tschemaVersion: number;\n\tindexUrl: string;\n\trevision: string;\n\tfetchedAt: number;\n\tetag?: string;\n\tlastModified?: string;\n\tmodels: Record<string, Record<string, Model<Api>>>;\n}\n\nexport interface ModelCatalogRefreshOptions {\n\t/** URL of the upstream models/v1/index.json catalog index. Defaults to PI_MODEL_CATALOG_URL. */\n\tindexUrl?: string;\n\t/** Persistent cache file. Defaults to PI_MODEL_CATALOG_CACHE_PATH or ~/.cache/pi/model-catalog.json. */\n\tcachePath?: string;\n\t/** Reuse cache without a network request while it is this fresh. Default: 6 hours. */\n\tttlMs?: number;\n\t/** Ignore TTL and conditional validators. */\n\tforce?: boolean;\n\tsignal?: AbortSignal;\n\t/** Test hook. Defaults to global fetch. */\n\tfetch?: typeof fetch;\n\t/** Test hook. Defaults to Date.now(). */\n\tnow?: () => number;\n}\n\nexport interface ModelCatalogRefreshResult {\n\tloaded: boolean;\n\tupdated: boolean;\n\tfromCache: boolean;\n\trevision?: string;\n\tproviderCount: number;\n\tmodelCount: number;\n}\ninterface NodeDirectoryCreationOptions {\n\trecursive: boolean;\n}\n\ninterface ModelCatalogCounts {\n\tproviderCount: number;\n\tmodelCount: number;\n}\n\ntype NodeFs = {\n\texistsSync(path: string): boolean;\n\tmkdirSync(path: string, options: NodeDirectoryCreationOptions): void;\n\treadFileSync(path: string, encoding: BufferEncoding): string;\n\twriteFileSync(path: string, content: string): void;\n};\n\ntype NodeOs = { homedir(): string };\n\ntype NodePath = {\n\tdirname(path: string): string;\n\tjoin(...parts: string[]): string;\n};\n\nfunction getNodeBuiltin<T>(name: string): T | undefined {\n\treturn typeof process === \"undefined\" ? undefined : (process.getBuiltinModule?.(name) as T | undefined);\n}\n\nfunction getNodeModelCatalogCachePath(): string | undefined {\n\tconst os = getNodeBuiltin<NodeOs>(\"os\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!os || !path) return undefined;\n\treturn path.join(os.homedir(), \".cache\", \"pi\", \"model-catalog.json\");\n}\n\nconst modelRegistry: Map<string, Map<string, Model<Api>>> = new Map();\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isFinitePositiveNumber(value: unknown): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\nfunction isModelInput(value: unknown): boolean {\n\treturn Array.isArray(value) && value.every((entry) => entry === \"text\" || entry === \"image\");\n}\n\nfunction isModelCost(value: unknown): boolean {\n\tif (!isRecord(value)) return false;\n\tfor (const field of [\"input\", \"output\", \"cacheRead\", \"cacheWrite\"] as const) {\n\t\tif (typeof value[field] !== \"number\" || !Number.isFinite(value[field])) return false;\n\t}\n\treturn true;\n}\n\nfunction isModel(value: unknown, provider: string, id: string): value is Model<Api> {\n\tif (!isRecord(value)) return false;\n\tif (value.id !== id || value.provider !== provider) return false;\n\tif (typeof value.name !== \"string\" || value.name.length === 0) return false;\n\tif (typeof value.api !== \"string\" || value.api.length === 0) return false;\n\tif (typeof value.baseUrl !== \"string\" || value.baseUrl.length === 0) return false;\n\tif (typeof value.reasoning !== \"boolean\") return false;\n\tif (!isModelInput(value.input)) return false;\n\tif (!isModelCost(value.cost)) return false;\n\treturn isFinitePositiveNumber(value.contextWindow) && isFinitePositiveNumber(value.maxTokens);\n}\n\nfunction validateCatalogModels(value: unknown): Record<string, Record<string, Model<Api>>> {\n\tif (!isRecord(value)) throw new Error(\"Model catalog must contain an object\");\n\tconst providers: Record<string, Record<string, Model<Api>>> = {};\n\tfor (const [provider, providerModels] of Object.entries(value)) {\n\t\tif (!isRecord(providerModels)) throw new Error(`Model catalog provider must contain an object: ${provider}`);\n\t\tconst models: Record<string, Model<Api>> = {};\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tif (!isModel(model, provider, id)) throw new Error(`Invalid model catalog entry: ${provider}/${id}`);\n\t\t\tmodels[id] = model;\n\t\t}\n\t\tproviders[provider] = models;\n\t}\n\treturn providers;\n}\n\nfunction countCatalogModels(models: Record<string, Record<string, Model<Api>>>): ModelCatalogCounts {\n\tlet modelCount = 0;\n\tfor (const providerModels of Object.values(models)) modelCount += Object.keys(providerModels).length;\n\treturn { providerCount: Object.keys(models).length, modelCount };\n}\n\nfunction applyCatalogModels(models: Record<string, Record<string, Model<Api>>>): void {\n\tfor (const [provider, providerModels] of Object.entries(models)) {\n\t\tconst registryProviderModels = modelRegistry.get(provider) ?? new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(providerModels)) {\n\t\t\tregistryProviderModels.set(id, model);\n\t\t}\n\t\tmodelRegistry.set(provider, registryProviderModels);\n\t}\n}\n\nfunction readCachedCatalog(cachePath: string | undefined, indexUrl?: string): CachedModelCatalog | undefined {\n\ttry {\n\t\tif (!cachePath) return undefined;\n\t\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\t\tif (!fs?.existsSync(cachePath)) return undefined;\n\t\tconst parsed = JSON.parse(fs.readFileSync(cachePath, \"utf8\")) as unknown;\n\t\tif (!isRecord(parsed)) return undefined;\n\t\tif (parsed.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) return undefined;\n\t\tif (typeof parsed.indexUrl !== \"string\" || typeof parsed.revision !== \"string\") return undefined;\n\t\tif (indexUrl !== undefined && parsed.indexUrl !== indexUrl) return undefined;\n\t\tif (typeof parsed.fetchedAt !== \"number\" || !Number.isFinite(parsed.fetchedAt)) return undefined;\n\t\tconst cached: CachedModelCatalog = {\n\t\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\t\tindexUrl: parsed.indexUrl,\n\t\t\trevision: parsed.revision,\n\t\t\tfetchedAt: parsed.fetchedAt,\n\t\t\tmodels: validateCatalogModels(parsed.models),\n\t\t};\n\t\tif (typeof parsed.etag === \"string\") cached.etag = parsed.etag;\n\t\tif (typeof parsed.lastModified === \"string\") cached.lastModified = parsed.lastModified;\n\t\treturn cached;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction writeCachedCatalog(cachePath: string | undefined, catalog: CachedModelCatalog): void {\n\tconst fs = getNodeBuiltin<NodeFs>(\"fs\");\n\tconst path = getNodeBuiltin<NodePath>(\"path\");\n\tif (!cachePath || !fs || !path) return;\n\tfs.mkdirSync(path.dirname(cachePath), { recursive: true });\n\tfs.writeFileSync(cachePath, `${JSON.stringify(catalog, null, 2)}\\n`);\n}\n\nfunction getCachePath(options?: Pick<ModelCatalogRefreshOptions, \"cachePath\">): string | undefined {\n\tconst envPath = typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_CACHE_PATH;\n\treturn options?.cachePath ?? envPath ?? getNodeModelCatalogCachePath();\n}\n\nfunction getIndexUrl(options?: Pick<ModelCatalogRefreshOptions, \"indexUrl\">): string | undefined {\n\treturn options?.indexUrl ?? (typeof process === \"undefined\" ? undefined : process.env.PI_MODEL_CATALOG_URL);\n}\n\nfunction resolveCatalogUrl(indexUrl: string, revision: string): string {\n\treturn new URL(`revisions/${encodeURIComponent(revision)}/models.json`, indexUrl).toString();\n}\n\nfunction selectRevision(index: ModelCatalogIndex): string | undefined {\n\treturn index.defaultRevision ?? index.catalogs?.at(-1)?.revision;\n}\n\nfunction createResult(\n\tmodels: Record<string, Record<string, Model<Api>>> | undefined,\n\tresult: Pick<ModelCatalogRefreshResult, \"loaded\" | \"updated\" | \"fromCache\" | \"revision\">,\n): ModelCatalogRefreshResult {\n\tconst counts = models ? countCatalogModels(models) : { providerCount: 0, modelCount: 0 };\n\treturn { ...result, ...counts };\n}\n\nfunction getFreshCatalogCache(\n\toptions: ModelCatalogRefreshOptions,\n\tcached: CachedModelCatalog | undefined,\n\tnow: number,\n\tttlMs: number,\n): CachedModelCatalog | undefined {\n\tif (options.force || !cached || now - cached.fetchedAt >= ttlMs) return undefined;\n\treturn cached;\n}\n\nfunction createConditionalCatalogHeaders(\n\toptions: ModelCatalogRefreshOptions,\n\tcached: CachedModelCatalog | undefined,\n): Record<string, string> {\n\tconst headers: Record<string, string> = {};\n\tif (!options.force && cached?.etag) headers[\"If-None-Match\"] = cached.etag;\n\tif (!options.force && cached?.lastModified) headers[\"If-Modified-Since\"] = cached.lastModified;\n\treturn headers;\n}\n\nfunction reuseCachedCatalog(\n\tcachePath: string | undefined,\n\tcached: CachedModelCatalog,\n\tfetchedAt: number,\n): ModelCatalogRefreshResult {\n\tconst refreshedCache = { ...cached, fetchedAt };\n\twriteCachedCatalog(cachePath, refreshedCache);\n\tapplyCatalogModels(refreshedCache.models);\n\treturn createResult(refreshedCache.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: refreshedCache.revision,\n\t});\n}\n\nfunction validateCatalogIndex(value: unknown): ModelCatalogIndex {\n\tif (!isRecord(value) || value.schemaVersion !== MODEL_CATALOG_SCHEMA_VERSION) {\n\t\tthrow new Error(\"Unsupported model catalog index schema\");\n\t}\n\treturn value as unknown as ModelCatalogIndex;\n}\n\nfunction initializeStaticRegistry(): void {\n\tmodelRegistry.clear();\n\tfor (const [provider, models] of Object.entries(MODELS)) {\n\t\tconst providerModels = new Map<string, Model<Api>>();\n\t\tfor (const [id, model] of Object.entries(models)) {\n\t\t\tproviderModels.set(id, model as Model<Api>);\n\t\t}\n\t\tmodelRegistry.set(provider, providerModels);\n\t}\n}\n\ninitializeStaticRegistry();\n\n/**\n * Load a previously refreshed model catalog from disk and overlay it on the generated catalog.\n * This is synchronous so callers can update built-in model lists before constructing registries.\n */\nexport function loadCachedModelCatalog(\n\toptions: Pick<ModelCatalogRefreshOptions, \"cachePath\" | \"indexUrl\"> = {},\n): ModelCatalogRefreshResult {\n\tconst cached = readCachedCatalog(getCachePath(options), getIndexUrl(options));\n\tif (!cached) return createResult(undefined, { loaded: false, updated: false, fromCache: true });\n\tapplyCatalogModels(cached.models);\n\treturn createResult(cached.models, {\n\t\tloaded: true,\n\t\tupdated: false,\n\t\tfromCache: true,\n\t\trevision: cached.revision,\n\t});\n}\n\n/** Reset runtime overlays. Intended for tests. */\nexport function resetModelCatalog(): void {\n\tinitializeStaticRegistry();\n}\n\n/**\n * Fetch an upstream model catalog index, cache the selected revision, and overlay it on generated models.\n * The upstream format matches the catalog produced by the publish-model-catalog workflow.\n */\nexport async function refreshModelCatalog(\n\toptions: ModelCatalogRefreshOptions = {},\n): Promise<ModelCatalogRefreshResult> {\n\tconst indexUrl = getIndexUrl(options);\n\tif (!indexUrl) return createResult(undefined, { loaded: false, updated: false, fromCache: false });\n\tconst cachePath = getCachePath(options);\n\tconst cached = readCachedCatalog(cachePath, indexUrl);\n\tconst now = options.now?.() ?? Date.now();\n\tconst ttlMs = options.ttlMs ?? 6 * 60 * 60 * 1000;\n\tconst freshCache = getFreshCatalogCache(options, cached, now, ttlMs);\n\tif (freshCache) {\n\t\tapplyCatalogModels(freshCache.models);\n\t\treturn createResult(freshCache.models, {\n\t\t\tloaded: true,\n\t\t\tupdated: false,\n\t\t\tfromCache: true,\n\t\t\trevision: freshCache.revision,\n\t\t});\n\t}\n\n\tconst fetchImpl = options.fetch ?? fetch;\n\tconst headers = createConditionalCatalogHeaders(options, cached);\n\tconst indexResponse = await fetchImpl(indexUrl, { headers, signal: options.signal });\n\tif (indexResponse.status === 304 && cached) return reuseCachedCatalog(cachePath, cached, now);\n\tif (!indexResponse.ok) throw new Error(`Model catalog index request failed: ${indexResponse.status}`);\n\tconst index = validateCatalogIndex(await indexResponse.json());\n\tconst revision = selectRevision(index);\n\tif (!revision) throw new Error(\"Model catalog index does not contain a revision\");\n\tif (!options.force && cached?.revision === revision) return reuseCachedCatalog(cachePath, cached, now);\n\n\tconst catalogResponse = await fetchImpl(resolveCatalogUrl(indexUrl, revision), { signal: options.signal });\n\tif (!catalogResponse.ok) throw new Error(`Model catalog request failed: ${catalogResponse.status}`);\n\tconst models = validateCatalogModels(await catalogResponse.json());\n\tconst nextCached: CachedModelCatalog = {\n\t\tschemaVersion: MODEL_CATALOG_SCHEMA_VERSION,\n\t\tindexUrl,\n\t\trevision,\n\t\tfetchedAt: now,\n\t\tmodels,\n\t};\n\tconst etag = indexResponse.headers.get(\"etag\");\n\tif (etag) nextCached.etag = etag;\n\tconst lastModified = indexResponse.headers.get(\"last-modified\");\n\tif (lastModified) nextCached.lastModified = lastModified;\n\twriteCachedCatalog(cachePath, nextCached);\n\tapplyCatalogModels(models);\n\treturn createResult(models, { loaded: true, updated: true, fromCache: false, revision });\n}\n\ntype ModelApi<\n\tTProvider extends KnownProvider,\n\tTModelId extends keyof (typeof MODELS)[TProvider],\n> = (typeof MODELS)[TProvider][TModelId] extends { api: infer TApi } ? (TApi extends Api ? TApi : never) : never;\n\nexport function getModel<TProvider extends KnownProvider, TModelId extends keyof (typeof MODELS)[TProvider]>(\n\tprovider: TProvider,\n\tmodelId: TModelId,\n): Model<ModelApi<TProvider, TModelId>> {\n\tconst providerModels = modelRegistry.get(provider);\n\treturn providerModels?.get(modelId as string) as Model<ModelApi<TProvider, TModelId>>;\n}\n\nexport function getProviders(): KnownProvider[] {\n\treturn Array.from(modelRegistry.keys()) as KnownProvider[];\n}\n\nexport function getModels<TProvider extends KnownProvider>(\n\tprovider: TProvider,\n): Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[] {\n\tconst models = modelRegistry.get(provider);\n\treturn models ? (Array.from(models.values()) as Model<ModelApi<TProvider, keyof (typeof MODELS)[TProvider]>>[]) : [];\n}\n\nexport function calculateCost<TApi extends Api>(model: Model<TApi>, usage: Usage): UsageCost {\n\tusage.cost.input = (model.cost.input / 1000000) * usage.input;\n\tusage.cost.output = (model.cost.output / 1000000) * usage.output;\n\tusage.cost.cacheRead = (model.cost.cacheRead / 1000000) * usage.cacheRead;\n\tusage.cost.cacheWrite = (model.cost.cacheWrite / 1000000) * usage.cacheWrite;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n\treturn usage.cost;\n}\n\nconst EXTENDED_THINKING_LEVELS: ModelThinkingLevel[] = [\"off\", \"minimal\", \"low\", \"medium\", \"high\", \"xhigh\"];\n\nexport function getSupportedThinkingLevels<TApi extends Api>(model: Model<TApi>): ModelThinkingLevel[] {\n\tif (!model.reasoning) return [\"off\"];\n\n\treturn EXTENDED_THINKING_LEVELS.filter((level) => {\n\t\tconst mapped = model.thinkingLevelMap?.[level];\n\t\tif (mapped === null) return false;\n\t\tif (level === \"xhigh\") return mapped !== undefined;\n\t\treturn true;\n\t});\n}\n\nexport function clampThinkingLevel<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tlevel: ModelThinkingLevel,\n): ModelThinkingLevel {\n\tconst availableLevels = getSupportedThinkingLevels(model);\n\tconst availableLevelSet = new Set(availableLevels);\n\tif (availableLevelSet.has(level)) return level;\n\n\tconst requestedIndex = EXTENDED_THINKING_LEVELS.indexOf(level);\n\tif (requestedIndex === -1) return availableLevels[0] ?? \"off\";\n\n\tfor (let i = requestedIndex; i < EXTENDED_THINKING_LEVELS.length; i++) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevelSet.has(candidate)) return candidate;\n\t}\n\tfor (let i = requestedIndex - 1; i >= 0; i--) {\n\t\tconst candidate = EXTENDED_THINKING_LEVELS[i];\n\t\tif (availableLevelSet.has(candidate)) return candidate;\n\t}\n\treturn availableLevels[0] ?? \"off\";\n}\n\n/**\n * Check if two models are equal by comparing both their id and provider.\n * Returns false if either model is null or undefined.\n */\nexport function modelsAreEqual<TApi extends Api>(\n\ta: Model<TApi> | null | undefined,\n\tb: Model<TApi> | null | undefined,\n): boolean {\n\tif (!a || !b) return false;\n\treturn a.id === b.id && a.provider === b.provider;\n}\n"]}