mirror of
https://github.com/mark3labs/kit.git
synced 2026-06-14 03:30:26 +00:00
feat(models): resolve SDK default URLs for all registered providers
- Add sdkDefaultBaseURL map covering the 14 npm SDKs that ship a
hard-coded baseURL (groq, cerebras, mistral, xai, perplexity,
togetherai, deepinfra, cohere, v0, aihubmix, venice, merge-gateway,
openrouter, vercel gateway), so providers whose models.dev entry
omits the api field still auto-route correctly.
- Extend npmToWireProtocol so these thin OpenAI-compatible wrappers
route through fantasy's openaicompat provider.
- Add resolveTemplatedAPIURL to substitute ${VAR} placeholders for
cloudflare-workers-ai, databricks, snowflake-cortex from the env,
with friendly errors that name the missing vars.
- Wire amazon-bedrock and azure-cognitive-services aliases into the
existing native handlers; add createGoogleVertexProvider for the
google-vertex case.
- Expose kit.ResolveProviderBaseURL in the public SDK so embedders
can introspect the effective endpoint before instantiating a Kit.
- Refresh embedded_models.json from models.dev (5113 -> 5121 models;
139 providers unchanged).
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
cel.dev/expr v0.25.2/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||
charm.land/bubbles/v2 v2.1.0 h1:YSnNh5cPYlYjPxRrzs5VEn3vwhtEn3jVGRBT3M7/I0g=
|
||||
charm.land/bubbles/v2 v2.1.0/go.mod h1:l97h4hym2hvWBVfmJDtrEHHCtkIKeTEb3TTJ4ZOB3wY=
|
||||
charm.land/bubbletea/v2 v2.0.7 h1:7qw2tTAVar7m7klOPBYfTB0mniv/RuexsYwMRNxSeL0=
|
||||
@@ -8,6 +9,7 @@ charm.land/huh/v2 v2.0.3 h1:2cJsMqEPwSywGHvdlKsJyQKPtSJLVnFKyFbsYZTlLkU=
|
||||
charm.land/huh/v2 v2.0.3/go.mod h1:93eEveeeqn47MwiC3tf+2atZ2l7Is88rAtmZNZ8x9Wc=
|
||||
charm.land/lipgloss/v2 v2.0.3 h1:yM2zJ4Cf5Y51b7RHIwioil4ApI/aypFXXVHSwlM6RzU=
|
||||
charm.land/lipgloss/v2 v2.0.3/go.mod h1:7myLU9iG/3xluAWzpY/fSxYYHCgoKTie7laxk6ATwXA=
|
||||
charm.land/x/vcr v0.1.1/go.mod h1:eByq2gqzWvcct/8XE2XO5KznoWEBiXH56+y2gphbltM=
|
||||
cloud.google.com/go v0.123.0 h1:2NAUJwPR47q+E35uaJeYoNhuNEM9kM8SjgRgdeOJUSE=
|
||||
cloud.google.com/go v0.123.0/go.mod h1:xBoMV08QcqUGuPW65Qfm1o9Y4zKZBpGS+7bImXLTAZU=
|
||||
cloud.google.com/go/auth v0.20.0 h1:kXTssoVb4azsVDoUiF8KvxAqrsQcQtB53DcSgta74CA=
|
||||
@@ -16,6 +18,11 @@ cloud.google.com/go/auth/oauth2adapt v0.2.8 h1:keo8NaayQZ6wimpNSmW5OPc283g65QNIi
|
||||
cloud.google.com/go/auth/oauth2adapt v0.2.8/go.mod h1:XQ9y31RkqZCcwJWNSx2Xvric3RrU88hAYYbjDWYDL+c=
|
||||
cloud.google.com/go/compute/metadata v0.9.0 h1:pDUj4QMoPejqq20dK0Pg2N4yG9zIkYGdBtwLoEkH9Zs=
|
||||
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||
cloud.google.com/go/iam v1.11.0/go.mod h1:KP+nKGugNJW4LcLx1uEZcq1ok5sQHFaQehQNl4QDgV4=
|
||||
cloud.google.com/go/longrunning v0.5.6/go.mod h1:vUaDrWYOMKRuhiv6JBnn49YxCPz2Ayn9GqyjaBT8/mA=
|
||||
cloud.google.com/go/monitoring v1.29.0/go.mod h1:72NOVjJXHY/HBfoLT0+qlCZBT059+9VXLeAnL2PeeVM=
|
||||
cloud.google.com/go/storage v1.62.1/go.mod h1:cpYz/kRVZ+UQAF1uHeea10/9ewcRbxGoGNKsS9daSXA=
|
||||
cloud.google.com/go/translate v1.10.3/go.mod h1:GW0vC1qvPtd3pgtypCv4k4U8B7EdgK9/QEF2aJEUovs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1 h1:jHb/wfvRikGdxMXYV3QG/SzUOPYN9KEUUuC0Yd0/vC0=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.21.1/go.mod h1:pzBXCYn05zvYIrwLgtK8Ap8QcjRg+0i76tMQdWN6wOk=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.13.1 h1:Hk5QBxZQC1jb2Fwj6mpzme37xbCDdNTxU7O9eb5+LB4=
|
||||
@@ -24,14 +31,20 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0 h1:fhqpLE3UEXi9lPaBRpQ6Xu
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.12.0/go.mod h1:7dCRMLwisfRH3dBupKeNCioWYUZ4SS09Z14H+7i8ZoY=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0 h1:XRzhVemXdgvJqCH0sFfrBUTnUJSBrBf7++ypk+twtRs=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.6.0/go.mod h1:HKpQxkWaGLJ+D/5H8QRpyQXA1eKjxkFlOMwck5+33Jk=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.32.0/go.mod h1:RD2SsorTmYhF6HkTmDw7KmPYQk8OBYwTkuasChwv7R4=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/exporter/metric v0.56.0/go.mod h1:hEpiGU18xf70qb3jbTcIggWAiEfX/cOIVc2OTe4OegA=
|
||||
github.com/GoogleCloudPlatform/opentelemetry-operations-go/internal/resourcemapping v0.56.0/go.mod h1:6ZZMQhZKDvUvkJw2rc+oDP90tMMzuU/J+5HG1ZmPOmE=
|
||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||
github.com/Rhymond/go-money v1.0.15/go.mod h1:iHvCuIvitxu2JIlAlhF0g9jHqjRSr+rpdOs7Omqlupg=
|
||||
github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0=
|
||||
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
|
||||
github.com/alecthomas/chroma/v2 v2.26.1 h1:2X21EdxGZNv5GF9mG5u+uzc02GCFyGxbcBm3Grd9A78=
|
||||
github.com/alecthomas/chroma/v2 v2.26.1/go.mod h1:lxhRRa9H4hPmRLOOdYga4zkQIQjq3dtrrdwQeCfu78Y=
|
||||
github.com/alecthomas/repr v0.5.2 h1:SU73FTI9D1P5UNtvseffFSGmdNci/O6RsqzeXJtP0Qs=
|
||||
github.com/alecthomas/repr v0.5.2/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||
github.com/ardanlabs/jinja v1.2.0/go.mod h1:aXXzlJfjA+T3XNKA/YT5ZtDq2VJxt5a5siZ8cl9B35Q=
|
||||
github.com/ardanlabs/kronk v1.25.2/go.mod h1:b5Gg4jDqvHDklkeHNB8+7treZRxUiCFsV65zphrTloY=
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/aws/aws-sdk-go-v2 v1.41.8 h1:sRs7nG6/RiEBZ/K5UO2sNw0w40U02Nmz1VtARloTZXk=
|
||||
@@ -48,12 +61,16 @@ github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.24 h1:u6kJU2i0va1AgtJsH
|
||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.24/go.mod h1:7GY+xLcXOFUpCkNwDReft9qOAVg54A4/AnjHIU7sSAY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.24 h1:Xhbcf3KugX6vX7SDyUK205Oicyfg7EGuvoVNyP5L6DM=
|
||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.24/go.mod h1:rwDgb2HNOGZsnTHylOUedM7Vnl+bCfnXDqUNPsFWYfk=
|
||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0/go.mod h1:8tu/lYfQfFe6IGnaOdrpVgEL2IrrDOf6/m9RQum4NkY=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.25 h1:54CTMmlJ71Rk2dYvM9qZOob+39wjlVja2zDLxCu69Ew=
|
||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.25/go.mod h1:BZaHqxsS9vN1fvV5EfEl0OBLOk5+AajWsMu6MjqnZB4=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9 h1:FLudkZLt5ci0ozzgkVo8BJGwvqNaZbTWb3UcucAateA=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.9/go.mod h1:w7wZ/s9qK7c8g4al+UyoF1Sp/Z45UwMGcqIzLWVQHWk=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.15/go.mod h1:e3IzZvQ3kAWNykvE0Tr0RDZCMFInMvhku3qNpcIQXhM=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.24 h1:CQW2FTrflfoslYWLf3fv7vG28Q219+v8YJS5QTQb2+Y=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.24/go.mod h1:Xfx13T+u3nH6EEzgl9fBSO6nDRmze1FvnZNYkctQ2zw=
|
||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.23/go.mod h1:M8l3mwgx5ToK7wot2sBBce/ojzgnPzZXUV445gTSyE8=
|
||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.101.0/go.mod h1:L2dcoOgS2VSgbPLvpak2NyUPsO1TBN7M45Z4H7DlRc4=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.0 h1:yQo3eZ5qFaL1sJWqs1nL6j3yPHA2/R7c6tQ4T+0IO10=
|
||||
github.com/aws/aws-sdk-go-v2/service/signin v1.1.0/go.mod h1:3Zzou41Qt/ueXfIzHvTEjDNuR5IjCUBVF01SNhrt1e8=
|
||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.18 h1:ApLTFdAZfDhZSiY5uskwECKHkSNNF83y2Ru2r7SezWA=
|
||||
@@ -68,8 +85,14 @@ github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiE
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1 h1:OEIrQ8maEeDBXQDoGCbbTTXYJMYRCRO1fnodZ12Gv5o=
|
||||
github.com/aymanbagabas/go-udiff v0.4.1/go.mod h1:0L9PGwj20lrtmEMeyw4WKJ/TMyDtvAoK9bf2u/mNo3w=
|
||||
github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d/go.mod h1:6QX/PXZ00z/TKoufEY6K/a0k6AhaJrQKdFe6OfVXsa4=
|
||||
github.com/bits-and-blooms/bitset v1.24.4/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8=
|
||||
github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx27UK13J/0=
|
||||
github.com/catppuccin/go v0.3.0 h1:d+0/YicIq+hSTo5oPuRi5kOpqkVA5tAsU6dNhvRu+aY=
|
||||
github.com/catppuccin/go v0.3.0/go.mod h1:8IHJuMGaUUjQM82qBrGNBv7LFq6JI3NnQCF6MOlZjpc=
|
||||
github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/anthropic-sdk-go v0.0.0-20260223140439-63879b0b8dab h1:J7XQLgl9sefgTnTGrmX3xqvp5o6MCiBzEjGv5igAlc4=
|
||||
@@ -120,6 +143,7 @@ github.com/charmbracelet/x/xpty v0.1.3 h1:eGSitii4suhzrISYH50ZfufV3v085BXQwIytcO
|
||||
github.com/charmbracelet/x/xpty v0.1.3/go.mod h1:poPYpWuLDBFCKmKLDnhBp51ATa0ooD8FhypRwEFtH3Y=
|
||||
github.com/clipperhouse/displaywidth v0.11.0 h1:lBc6kY44VFw+TDx4I8opi/EtL9m20WSEFgwIwO+UVM8=
|
||||
github.com/clipperhouse/displaywidth v0.11.0/go.mod h1:bkrFNkf81G8HyVqmKGxsPufD3JhNl3dSqnGhOoSD/o0=
|
||||
github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
|
||||
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
|
||||
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 h1:aBangftG7EVZoUb69Os8IaYg++6uMOdKK83QtkkvJik=
|
||||
@@ -137,11 +161,16 @@ github.com/dlclark/regexp2/v2 v2.1.1 h1:LCUGyd9Wf+r+VVOl8Ny38JTpWJcAsdVnCIuhhtth
|
||||
github.com/dlclark/regexp2/v2 v2.1.1/go.mod h1:avUrQvPaLz2DrFNHJF0taWAFFX2C1GMSSoeiqFjcBmU=
|
||||
github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI=
|
||||
github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ=
|
||||
github.com/dromara/carbon/v2 v2.6.16/go.mod h1:NGo3reeV5vhWCYWcSqbJRZm46MEwyfYI5EJRdVFoLJo=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
|
||||
github.com/eliben/go-sentencepiece v0.6.0/go.mod h1:nNYk4aMzgBoI6QFp4LUG8Eu1uO9fHD9L5ZEre93o9+c=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0 h1:hbG2kr4RuFj222B6+7T83thSPqLjwBIfQawTkC++2HA=
|
||||
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0 h1:u3riX6BoYRfF4Dr7dwSOroNfdSbEPe9Yyl09/B6wBrQ=
|
||||
github.com/envoyproxy/go-control-plane/envoy v1.37.0/go.mod h1:DReE9MMrmecPy+YvQOAOHNYMALuowAnbjjEMkkWOi6A=
|
||||
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3 h1:MVQghNeW+LZcmXe7SY1V36Z+WFMDjpqGAGacLe2T0ds=
|
||||
github.com/envoyproxy/protoc-gen-validate v1.3.3/go.mod h1:TsndJ/ngyIdQRhMcVVGDDHINPLWB7C82oDArY51KfB0=
|
||||
github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg=
|
||||
@@ -150,6 +179,7 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.10.1 h1:b0/UzAf9yR5rhf3RPm9gf3ehBPpf0oZKIjtpKrx59Ho=
|
||||
github.com/fsnotify/fsnotify v1.10.1/go.mod h1:TLheqan6HD6GBK6PrDWyDPBaEV8LspOxvPSjC+bVfgo=
|
||||
github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||
github.com/go-json-experiment/json v0.0.0-20260520185125-572e7c383686 h1:NZBJxCpbHS1gzS6xAmyxbJznosZIIPk9IB42v62UvKA=
|
||||
github.com/go-json-experiment/json v0.0.0-20260520185125-572e7c383686/go.mod h1:tphK2c80bpPhMOI4v6bIc2xWywPfbqi1Z06+RcrMkDg=
|
||||
github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE=
|
||||
@@ -165,12 +195,17 @@ github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
|
||||
github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/go-pkcs11 v0.3.0/go.mod h1:6eQoGcuNJpa7jnd5pMGdkSaQpNDYvPlXWMcjXXThLlY=
|
||||
github.com/google/jsonschema-go v0.4.3 h1:/DBOLZTfDow7pe2GmaJNhltueGTtDKICi8V8p+DQPd0=
|
||||
github.com/google/jsonschema-go v0.4.3/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE=
|
||||
github.com/google/martian/v3 v3.3.3/go.mod h1:iEPrYcgCF7jA9OtScMFQyAlZZ4YXTKEtJ1E6RWzmBA0=
|
||||
github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
|
||||
github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
@@ -181,14 +216,23 @@ github.com/googleapis/gax-go/v2 v2.22.0 h1:PjIWBpgGIVKGoCXuiCoP64altEJCj3/Ei+kSU
|
||||
github.com/googleapis/gax-go/v2 v2.22.0/go.mod h1:irWBbALSr0Sk3qlqb9SyJ1h68WjgeFuiOzI4Rqw5+aY=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.29.0/go.mod h1:Hyl3n6Twe1hvtd9XUXDec4pTvgMSEixRuQKPTMH2bNs=
|
||||
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.72/go.mod h1:Vn+BBgKQHVQYdVQ4NZDICE1Brb+JfaONyDHr3q07oQc=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.8.6/go.mod h1:nVH12eOV2P58dIiL3rsU6Fh3wLeJEKBOJzhMmzlSWoo=
|
||||
github.com/hashicorp/go-version v1.9.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/hybridgroup/yzma v1.13.0/go.mod h1:zrzMgv/KVQz23+s6l16b+vJ+9uJVBdWtGcGkwRTMeiQ=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/indaco/herald v0.13.0 h1:+xVG9Fx5NpuWhwku/9IlRL6I009NnX4VUGKvlZHTRxU=
|
||||
github.com/indaco/herald v0.13.0/go.mod h1:T5g1+XLYvpjouhzAGHnAHDCKizhESkoV6+QPZ3DhgWA=
|
||||
github.com/indaco/herald-md v0.3.0 h1:hN1cKyrexPPM9PeHBsKuaWvIizSi/iYvM9yzRgtdb8M=
|
||||
github.com/indaco/herald-md v0.3.0/go.mod h1:RUHVaDSG45ymJjKyxpDwBocLXrZo93FB4OeYMsw9B9s=
|
||||
github.com/invopop/jsonschema v0.13.0/go.mod h1:ffZ5Km5SWWRAIN6wbDXItl95euhFz2uON45H2qjYt+0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/jupiterrider/ffi v0.7.0/go.mod h1:9dauhpOfNqrqk28fxuu0kkdeFtT9Qr4vbfigiuIXN7c=
|
||||
github.com/kaptinlin/go-i18n v0.4.5 h1:9tIlo5A0RXth+yZJO2MG7Bhpu/X9PlzQnGz/qyYWNoY=
|
||||
github.com/kaptinlin/go-i18n v0.4.5/go.mod h1:mU/7BH4molY5lGZYBwBRKAaiJ70dWRHuqmQ0/pFLGno=
|
||||
github.com/kaptinlin/jsonpointer v0.4.25 h1:iJ197e8n+WwqaqBsa53FqG3rPJCg5oijyFXEXNWWC3E=
|
||||
@@ -197,6 +241,7 @@ github.com/kaptinlin/jsonschema v0.7.13 h1:kahVXTy/rURL0XJjyQ9WELm59wEmXi6IY0TWs
|
||||
github.com/kaptinlin/jsonschema v0.7.13/go.mod h1:Uh0aUBusnhXDCEXJ2oimL/hx7YTo7F+sKniE+tM0ERc=
|
||||
github.com/kaptinlin/messageformat-go v0.6.0 h1:D6jiXFsKW4/JG2CMddv/F6Rev9KVbCRKEzzV5QOAcpc=
|
||||
github.com/kaptinlin/messageformat-go v0.6.0/go.mod h1:NKjwS6e9u7DRhAK+vydjDDwJ7UbdHhYjk/yk2WPuZPs=
|
||||
github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
@@ -205,12 +250,14 @@ github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0
|
||||
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0 h1:UtrWVfLdarDgc44HcS7pYloGHJUjHV/4FwW4TvVgFr4=
|
||||
github.com/lucasb-eyer/go-colorful v1.4.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mark3labs/mcp-go v0.54.1 h1:Ap/ptEB9FtWzFKM8NDsTA7QDxerQOC06eZigrTldVj0=
|
||||
github.com/mark3labs/mcp-go v0.54.1/go.mod h1:+8WclSK1ZUweCP3hvktSji8n8ABG/95QaEkeVE/Uwas=
|
||||
github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
|
||||
github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
|
||||
github.com/mattn/go-runewidth v0.0.24 h1:cpokDiIn0MGnhdHwuWnJBITySJ20QyNGnY2kR/ay2DU=
|
||||
github.com/mattn/go-runewidth v0.0.24/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4=
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE=
|
||||
github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA=
|
||||
@@ -225,6 +272,7 @@ github.com/muesli/roff v0.1.0 h1:YD0lalCotmYuF5HhZliKWlIx7IEhiXeSfq7hNjFqGF8=
|
||||
github.com/muesli/roff v0.1.0/go.mod h1:pjAHQM9hdUUwm/krAfrLGgJkXJ+YuhtsfZ42kieB2Ig=
|
||||
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
|
||||
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/pelletier/go-toml/v2 v2.3.1 h1:MYEvvGnQjeNkRF1qUuGolNtNExTDwct51yp7olPtrEc=
|
||||
github.com/pelletier/go-toml/v2 v2.3.1/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
@@ -233,6 +281,10 @@ github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 h1:GFCKgm
|
||||
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.23.2/go.mod h1:Tb1a6LWHB3/SPIzCoaDXI4I8UHKeFTEQ1YCr+0Gyqmg=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.67.5/go.mod h1:SjE/0MzDEEAyrdr5Gqc6G+sXI67maCxzaT3A2+HqjUw=
|
||||
github.com/prometheus/procfs v0.20.1/go.mod h1:o9EMBZGRyvDrSPH1RqdxhojkuXstoe4UlK79eF5TGGo=
|
||||
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
|
||||
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
|
||||
@@ -240,8 +292,10 @@ github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sagikazarmark/locafero v0.12.0 h1:/NQhBAkUb4+fH1jivKHWusDYFjMOOKU88eegjfxfHb4=
|
||||
github.com/sagikazarmark/locafero v0.12.0/go.mod h1:sZh36u/YSZ918v0Io+U9ogLYQJ9tLLBmM4eneO6WwsI=
|
||||
github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||
@@ -253,6 +307,7 @@ github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
@@ -270,20 +325,27 @@ github.com/tidwall/sjson v1.2.5 h1:kLy8mja+1c9jlljvWTlSazM7cKDRfJuR/bOJhcY5NcY=
|
||||
github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28=
|
||||
github.com/traefik/yaegi v0.16.1 h1:f1De3DVJqIDKmnasUF6MwmWv1dSEEat0wcpXhD2On3E=
|
||||
github.com/traefik/yaegi v0.16.1/go.mod h1:4eVhbPb3LnD2VigQjhYbEJ69vDRFdT2HQNrXx8eEwUY=
|
||||
github.com/ulikunitz/xz v0.5.15/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
|
||||
github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
|
||||
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4=
|
||||
github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4=
|
||||
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
|
||||
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||
github.com/zeebo/errs v1.4.0/go.mod h1:sgbWHsvVuTPHcqJJGQ1WhI5KbWlHYz+2+2C/LSEtCw4=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||
go.opentelemetry.io/contrib/detectors/gcp v1.43.0/go.mod h1:RyaZMFY7yi1kAs45S6mbFGz8O8rqB0dTY14uzvG4LCs=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0 h1:2yEATaop1/a1I4psnSLgWVPLWwCzkqWakgJy7xTDVy0=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.69.0/go.mod h1:D7J12YRapIekYyPWgGPlA/23pRmpSEZC5xJC/TTLI9U=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0 h1:8tvICD4vSTOOsNrsI4Ljf6C+6UKvpTEH5XY3JMoyPoo=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.69.0/go.mod h1:z9+yiacE0IHRqM4qFfkbt/JYlmYXgss8GY/jXoNuPJI=
|
||||
go.opentelemetry.io/otel v1.44.0 h1:JjwHmHpA4iZ3wBxluu2fbbE7j4kqlE8jXyAyPXH7HqU=
|
||||
go.opentelemetry.io/otel v1.44.0/go.mod h1:BMgjTHL9WPRlRjL2oZCBTL4whCGtXch2H4BhOPIAyYc=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.43.0/go.mod h1:AGmbycVGEsRx9mXMZ75CsOyhSP6MFIcj/6dnG+vhVjk=
|
||||
go.opentelemetry.io/otel/metric v1.44.0 h1:1w0gILTcHdr3YI+ixLyjemwrVnsMURbTZFrSYCdDdmc=
|
||||
go.opentelemetry.io/otel/metric v1.44.0/go.mod h1:8O7hanEPBNgEMmybD3s2VBKcgWOCsA6tzHBPODAiquo=
|
||||
go.opentelemetry.io/otel/sdk v1.44.0 h1:nHYwb9lK+fJPU/dnT6s7W7Z8itMWyqrnVfbheVYrZ58=
|
||||
@@ -292,14 +354,18 @@ go.opentelemetry.io/otel/sdk/metric v1.44.0 h1:3LlKgI+VjbVsjNRFZJZAJ30WjXC5VkNRk
|
||||
go.opentelemetry.io/otel/sdk/metric v1.44.0/go.mod h1:5B5pMARnXxKhltooO4xUuCBorl65a4EpnTalObqOigA=
|
||||
go.opentelemetry.io/otel/trace v1.44.0 h1:jxF5CsGYCe74MCRx2X4g7WsY/VBKRqqpNvXlX/6gtIk=
|
||||
go.opentelemetry.io/otel/trace v1.44.0/go.mod h1:oLl1jrMQAVo6v3GAggN+1VH9VIz9iUSvW53sW1Q8PIE=
|
||||
go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk=
|
||||
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
|
||||
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988=
|
||||
golang.org/x/crypto v0.52.0/go.mod h1:1QgfPxDqh0T2M/elOJtp9RvuR95kVjir0e6/BvEmGbc=
|
||||
golang.org/x/exp v0.0.0-20260603202125-055de637280b h1:v1uXiEBHo8QA0LiGCo7UgHMzHT4Kdfpl2zmtH5vaP1Q=
|
||||
golang.org/x/exp v0.0.0-20260603202125-055de637280b/go.mod h1:d2fgXJLVs4dYDHUk5lwMIfzRzSrWCfGZb0ZqeLa/Vcw=
|
||||
golang.org/x/image v0.41.0 h1:8wS72eGJMJaBxK6okTzd4WaXumUlTVlb753MlsSvTCo=
|
||||
golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA=
|
||||
golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
|
||||
golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8=
|
||||
golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww=
|
||||
golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs=
|
||||
@@ -314,16 +380,21 @@ golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
|
||||
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
|
||||
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||
golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
|
||||
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
|
||||
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
|
||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
||||
google.golang.org/api v0.282.0 h1:WmJiSVqUnKqJCpJOx7YADbXaC+9DDsnGSfllFSj7R2I=
|
||||
google.golang.org/api v0.282.0/go.mod h1:6Wssta4c5n9qHq5CBhmlai5h/PUa1djdDAIhYEHyvcM=
|
||||
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=
|
||||
google.golang.org/genai v1.58.0 h1:MNA3ZkRyr7MnRwZ9RNZ60p4+UMKV3yYRw6pyHq4pp0U=
|
||||
google.golang.org/genai v1.58.0/go.mod h1:A3kkl0nyBjyFlNjgxIwKq70julKbIxpSxqKO5gw/gmk=
|
||||
google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348 h1:JjVGDZYWkJWZcxveJGzfkXC5myDVWAd4dZdgbzrDUv8=
|
||||
google.golang.org/genproto v0.0.0-20260504160031-60b97b32f348/go.mod h1:95PqD4xM+AdOcBGsmgfaofXsiA37uXDtDufVbntT3TU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348 h1:U8orV30l6KpDsi9dxU0CoJZGbjS8EEpw+6ba+XwGPQA=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20260504160031-60b97b32f348/go.mod h1:Yzdzr5OOZFgSsEV2D/Xi9NL3bszpXFAg0hFJiRohcD8=
|
||||
google.golang.org/genproto/googleapis/bytestream v0.0.0-20260523011958-0a33c5d7ca68/go.mod h1:6TABGosqSqU2l1+fJ3jdvOYPPVryeKybxYF0cCZkTBE=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa h1:mZHHdPZl0dbGHCflZgAq/Q468DWVFcU2whhB2KAo8fk=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||
google.golang.org/grpc v1.81.1 h1:VnnIIZ88UzOOKLukQi+ImGz8O1Wdp8nAGGnvOfEIWQQ=
|
||||
@@ -333,6 +404,8 @@ google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/dnaeon/go-vcr.v4 v4.0.6-0.20251110073552-01de4eb40290/go.mod h1:sbq5oMEcM4PXngbcNbHhzfCP9OdZodLhrbRYoyg09HY=
|
||||
gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
@@ -10,15 +10,31 @@ import (
|
||||
)
|
||||
|
||||
// TestNpmToWireProtocol documents the wire protocols that the auto-router
|
||||
// understands. Provider-specific bundles (azure, bedrock, vercel, openrouter,
|
||||
// google-vertex*) are intentionally absent — they have native top-level cases
|
||||
// in CreateProvider and never reach the auto-router.
|
||||
// understands. Provider-specific bundles that need bespoke auth or URL
|
||||
// templating (azure, bedrock, openrouter, google-vertex*, @ai-sdk/gateway)
|
||||
// are intentionally absent — they have native top-level cases in
|
||||
// CreateProvider and never reach the auto-router.
|
||||
func TestNpmToWireProtocol(t *testing.T) {
|
||||
want := map[string]wireProtocol{
|
||||
"@ai-sdk/openai": wireOpenAI,
|
||||
"@ai-sdk/openai-compatible": wireOpenAI,
|
||||
"@ai-sdk/anthropic": wireAnthropic,
|
||||
"@ai-sdk/google": wireGoogle,
|
||||
|
||||
// Thin OpenAI-compatible wrappers — routed via openaicompat using
|
||||
// the SDK's hard-coded default base URL (sdkDefaultBaseURL).
|
||||
"@ai-sdk/groq": wireOpenAI,
|
||||
"@ai-sdk/cerebras": wireOpenAI,
|
||||
"@ai-sdk/perplexity": wireOpenAI,
|
||||
"@ai-sdk/togetherai": wireOpenAI,
|
||||
"@ai-sdk/xai": wireOpenAI,
|
||||
"@ai-sdk/deepinfra": wireOpenAI,
|
||||
"@ai-sdk/mistral": wireOpenAI,
|
||||
"@ai-sdk/cohere": wireOpenAI,
|
||||
"@ai-sdk/vercel": wireOpenAI,
|
||||
"@aihubmix/ai-sdk-provider": wireOpenAI,
|
||||
"venice-ai-sdk-provider": wireOpenAI,
|
||||
"merge-gateway-ai-sdk-provider": wireOpenAI,
|
||||
}
|
||||
for npm, wire := range want {
|
||||
if got := npmToWireProtocol[npm]; got != wire {
|
||||
@@ -26,15 +42,15 @@ func TestNpmToWireProtocol(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Bundle packages must NOT be in the table (regression guard against the
|
||||
// old npmToLLMProvider map that listed 10 entries but only handled 3).
|
||||
// Bundle packages must NOT be in the table — they need bespoke auth or
|
||||
// URL templating that the auto-router cannot satisfy.
|
||||
for _, npm := range []string{
|
||||
"@ai-sdk/google-vertex",
|
||||
"@ai-sdk/google-vertex/anthropic",
|
||||
"@ai-sdk/amazon-bedrock",
|
||||
"@ai-sdk/azure",
|
||||
"@openrouter/ai-sdk-provider",
|
||||
"@ai-sdk/vercel",
|
||||
"@ai-sdk/gateway",
|
||||
} {
|
||||
if _, ok := npmToWireProtocol[npm]; ok {
|
||||
t.Errorf("npmToWireProtocol unexpectedly contains bundle package %q", npm)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -62,14 +62,73 @@ const (
|
||||
)
|
||||
|
||||
// npmToWireProtocol maps npm package names from models.dev to the wire
|
||||
// protocol they speak. Provider-specific bundles (azure, bedrock, vercel,
|
||||
// openrouter, google-vertex, google-vertex-anthropic) are intentionally
|
||||
// absent — they have native top-level cases in CreateProvider and never
|
||||
// reach the auto-router. Providers not in this map but with an api URL
|
||||
// are auto-routed through the OpenAI-compatible wire.
|
||||
// protocol they speak. Provider-specific bundles that need bespoke auth or
|
||||
// URL templating (azure, bedrock, openrouter, google-vertex, google-vertex-
|
||||
// anthropic, and @ai-sdk/gateway which is the Vercel AI Gateway) are
|
||||
// intentionally absent — they have native top-level cases in CreateProvider
|
||||
// and never reach the auto-router. Providers not in this map but with an
|
||||
// api URL are auto-routed through the OpenAI-compatible wire.
|
||||
//
|
||||
// The thin OpenAI-compatible npm wrappers (groq, cerebras, mistral, …) are
|
||||
// listed explicitly so that auto-routing can recover their hard-coded base
|
||||
// URL from sdkDefaultBaseURL when the registry entry has no api field.
|
||||
var npmToWireProtocol = map[string]wireProtocol{
|
||||
// Native wires.
|
||||
"@ai-sdk/openai": wireOpenAI,
|
||||
"@ai-sdk/openai-compatible": wireOpenAI,
|
||||
"@ai-sdk/anthropic": wireAnthropic,
|
||||
"@ai-sdk/google": wireGoogle,
|
||||
|
||||
// Thin OpenAI-compatible wrappers. Each ships with a hard-coded base URL
|
||||
// in its JS SDK (see sdkDefaultBaseURL) but speaks the plain OpenAI chat
|
||||
// completions wire — so we can route them all through fantasy's
|
||||
// openaicompat provider once we supply the URL.
|
||||
"@ai-sdk/groq": wireOpenAI,
|
||||
"@ai-sdk/cerebras": wireOpenAI,
|
||||
"@ai-sdk/perplexity": wireOpenAI,
|
||||
"@ai-sdk/togetherai": wireOpenAI,
|
||||
"@ai-sdk/xai": wireOpenAI,
|
||||
"@ai-sdk/deepinfra": wireOpenAI,
|
||||
"@ai-sdk/mistral": wireOpenAI,
|
||||
"@ai-sdk/cohere": wireOpenAI,
|
||||
"@ai-sdk/vercel": wireOpenAI, // v0 API (api.v0.dev), distinct from @ai-sdk/gateway
|
||||
"@aihubmix/ai-sdk-provider": wireOpenAI,
|
||||
"venice-ai-sdk-provider": wireOpenAI,
|
||||
"merge-gateway-ai-sdk-provider": wireOpenAI,
|
||||
}
|
||||
|
||||
// sdkDefaultBaseURL maps an npm package name to the base URL its JavaScript
|
||||
// SDK uses by default. This lets us recover a working endpoint for providers
|
||||
// whose models.dev entry omits the `api` field because the JS SDK hard-codes
|
||||
// the URL (e.g. groq, cerebras, mistral, x.ai…).
|
||||
//
|
||||
// Only OpenAI-compatible and native-wire SDKs are listed; providers needing
|
||||
// bespoke auth or URL templating (bedrock SigV4, azure resource URLs,
|
||||
// google-vertex project/location, cloudflare gateway account IDs, gitlab,
|
||||
// sap-ai-core) are handled by native CreateProvider cases or surface a
|
||||
// targeted error that asks the user to supply --provider-url.
|
||||
var sdkDefaultBaseURL = map[string]string{
|
||||
// Native wires.
|
||||
"@ai-sdk/openai": "https://api.openai.com/v1",
|
||||
"@ai-sdk/anthropic": "https://api.anthropic.com/v1",
|
||||
"@ai-sdk/google": "https://generativelanguage.googleapis.com/v1beta",
|
||||
|
||||
// Thin OpenAI-compatible wrappers.
|
||||
"@ai-sdk/groq": "https://api.groq.com/openai/v1",
|
||||
"@ai-sdk/cerebras": "https://api.cerebras.ai/v1",
|
||||
"@ai-sdk/perplexity": "https://api.perplexity.ai",
|
||||
"@ai-sdk/togetherai": "https://api.together.xyz/v1",
|
||||
"@ai-sdk/xai": "https://api.x.ai/v1",
|
||||
"@ai-sdk/deepinfra": "https://api.deepinfra.com/v1/openai",
|
||||
"@ai-sdk/mistral": "https://api.mistral.ai/v1",
|
||||
"@ai-sdk/cohere": "https://api.cohere.com/compatibility/v1",
|
||||
"@ai-sdk/vercel": "https://api.v0.dev/v1",
|
||||
"@aihubmix/ai-sdk-provider": "https://aihubmix.com/v1",
|
||||
"venice-ai-sdk-provider": "https://api.venice.ai/api/v1",
|
||||
"merge-gateway-ai-sdk-provider": "https://api-gateway.merge.dev/v1/ai-sdk",
|
||||
|
||||
// Native handlers — included for ResolveProviderBaseURL introspection
|
||||
// even though CreateProvider routes these via dedicated cases.
|
||||
"@ai-sdk/gateway": "https://ai-gateway.vercel.sh/v1",
|
||||
"@openrouter/ai-sdk-provider": "https://openrouter.ai/api/v1",
|
||||
}
|
||||
|
||||
@@ -286,13 +286,15 @@ func CreateProvider(ctx context.Context, config *ProviderConfig) (*ProviderResul
|
||||
result, createErr = createGoogleProvider(ctx, config, modelName)
|
||||
case "ollama":
|
||||
result, createErr = createOllamaProvider(ctx, config, modelName)
|
||||
case "azure":
|
||||
case "azure", "azure-cognitive-services":
|
||||
result, createErr = createAzureProvider(ctx, config, modelName)
|
||||
case "google-vertex-anthropic":
|
||||
result, createErr = createVertexAnthropicProvider(ctx, config, modelName)
|
||||
case "google-vertex":
|
||||
result, createErr = createGoogleVertexProvider(ctx, config, modelName)
|
||||
case "openrouter":
|
||||
result, createErr = createOpenRouterProvider(ctx, config, modelName)
|
||||
case "bedrock":
|
||||
case "bedrock", "amazon-bedrock":
|
||||
result, createErr = createBedrockProvider(ctx, config, modelName)
|
||||
case "vercel":
|
||||
result, createErr = createVercelProvider(ctx, config, modelName)
|
||||
@@ -376,8 +378,27 @@ func autoRouteProvider(ctx context.Context, config *ProviderConfig, provider, mo
|
||||
}
|
||||
|
||||
// All three wires use the provider's API URL from models.dev as the base.
|
||||
if config.ProviderURL == "" && providerInfo.API != "" {
|
||||
// When the registry has none, fall back to the SDK's hard-coded default for
|
||||
// this npm package (covers groq, cerebras, mistral, x.ai, etc. — providers
|
||||
// whose JS SDK ships a built-in baseURL that models.dev doesn't restate).
|
||||
if config.ProviderURL == "" {
|
||||
if providerInfo.API != "" {
|
||||
config.ProviderURL = providerInfo.API
|
||||
} else if defaultURL, ok := sdkDefaultBaseURL[npmPackage]; ok {
|
||||
config.ProviderURL = defaultURL
|
||||
providerInfo.API = defaultURL // for downstream helpers that read info.API
|
||||
}
|
||||
}
|
||||
|
||||
// Provider templates a runtime account/region/deployment segment into the
|
||||
// URL (cloudflare-ai-gateway, databricks, snowflake-cortex, gitlab,
|
||||
// sap-ai-core). Resolve via environment variables, or surface a targeted
|
||||
// error pointing the user at the right knobs.
|
||||
if resolved, err := resolveTemplatedAPIURL(config.ProviderURL, providerInfo); err != nil {
|
||||
return nil, err
|
||||
} else if resolved != "" {
|
||||
config.ProviderURL = resolved
|
||||
providerInfo.API = resolved
|
||||
}
|
||||
|
||||
switch wire {
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"charm.land/fantasy/providers/google"
|
||||
)
|
||||
|
||||
// templatePlaceholderRe matches "${NAME}" placeholders in URL templates from
|
||||
// models.dev (e.g. "https://${DATABRICKS_HOST}/ai-gateway/mlflow/v1").
|
||||
var templatePlaceholderRe = regexp.MustCompile(`\$\{([A-Z0-9_]+)\}`)
|
||||
|
||||
// templateEnvVarOverrides supplies fallback environment variable names for
|
||||
// placeholders that providers commonly use under non-obvious env names.
|
||||
// The placeholder name itself is always tried first; this map adds extra
|
||||
// names to try when the placeholder doesn't match the canonical env var.
|
||||
var templateEnvVarOverrides = map[string][]string{
|
||||
"CLOUDFLARE_ACCOUNT_ID": {"CF_ACCOUNT_ID"},
|
||||
"CLOUDFLARE_GATEWAY_NAME": {"CF_GATEWAY", "CLOUDFLARE_GATEWAY"},
|
||||
"DATABRICKS_HOST": {"DATABRICKS_WORKSPACE_URL"},
|
||||
"SNOWFLAKE_ACCOUNT": {"SNOWFLAKE_ACCOUNT_ID"},
|
||||
}
|
||||
|
||||
// resolveTemplatedAPIURL substitutes "${VAR}" placeholders in apiURL with the
|
||||
// values of the named environment variables. Returns:
|
||||
// - ("", nil) when apiURL contains no placeholders (caller keeps current URL),
|
||||
// - (resolved, nil) when every placeholder was resolved,
|
||||
// - ("", error) when one or more placeholders are unset, with a message that
|
||||
// names the missing env vars and points at the relevant provider.
|
||||
//
|
||||
// The info parameter is used purely for error messaging (provider name).
|
||||
func resolveTemplatedAPIURL(apiURL string, info *ProviderInfo) (string, error) {
|
||||
if apiURL == "" || !strings.Contains(apiURL, "${") {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var missing []string
|
||||
resolved := templatePlaceholderRe.ReplaceAllStringFunc(apiURL, func(match string) string {
|
||||
// match is "${NAME}". Extract NAME.
|
||||
name := match[2 : len(match)-1]
|
||||
if v := os.Getenv(name); v != "" {
|
||||
return v
|
||||
}
|
||||
for _, alt := range templateEnvVarOverrides[name] {
|
||||
if v := os.Getenv(alt); v != "" {
|
||||
return v
|
||||
}
|
||||
}
|
||||
missing = append(missing, name)
|
||||
return match
|
||||
})
|
||||
|
||||
if len(missing) > 0 {
|
||||
providerName := info.ID
|
||||
if info.Name != "" {
|
||||
providerName = info.Name
|
||||
}
|
||||
return "", fmt.Errorf(
|
||||
"provider %s requires environment variable(s) %s to construct its API URL (%s); "+
|
||||
"set them or pass --provider-url to override",
|
||||
providerName, strings.Join(missing, ", "), apiURL,
|
||||
)
|
||||
}
|
||||
return resolved, nil
|
||||
}
|
||||
|
||||
// ResolveProviderBaseURL returns the base API URL kit will use when talking to
|
||||
// the given provider, applying the same resolution order as CreateProvider:
|
||||
//
|
||||
// 1. The provider's `api` field from the models.dev registry.
|
||||
// 2. The hard-coded default base URL of its npm SDK package (e.g.
|
||||
// @ai-sdk/groq → https://api.groq.com/openai/v1).
|
||||
// 3. Template substitution against the current process environment when the
|
||||
// URL contains "${VAR}" placeholders (e.g. cloudflare-workers-ai needs
|
||||
// CLOUDFLARE_ACCOUNT_ID).
|
||||
//
|
||||
// It returns an error when the provider is unknown, when no URL can be derived,
|
||||
// or when a templated URL has unset placeholders. The error message is suitable
|
||||
// for direct display to end users.
|
||||
//
|
||||
// Note: providers handled by bespoke auth schemes (amazon-bedrock SigV4,
|
||||
// azure resource URLs, google-vertex project/location, sap-ai-core customer
|
||||
// deployments) may return either an empty URL or a regional/templated URL —
|
||||
// the actual endpoint is finalised inside their native handlers and depends on
|
||||
// runtime credentials.
|
||||
func ResolveProviderBaseURL(providerID string) (string, error) {
|
||||
registry := GetGlobalRegistry()
|
||||
info := registry.GetProviderInfo(providerID)
|
||||
if info == nil {
|
||||
return "", fmt.Errorf("unknown provider: %s", providerID)
|
||||
}
|
||||
|
||||
apiURL := info.API
|
||||
if apiURL == "" {
|
||||
if defaultURL, ok := sdkDefaultBaseURL[info.NPM]; ok {
|
||||
apiURL = defaultURL
|
||||
}
|
||||
}
|
||||
|
||||
if apiURL == "" {
|
||||
return "", fmt.Errorf(
|
||||
"provider %s has no default API URL: its npm package %q does not "+
|
||||
"ship a built-in baseURL (likely Bedrock SigV4, Azure deployment, "+
|
||||
"Vertex project/location, or a customer-hosted endpoint). "+
|
||||
"Pass --provider-url or set the provider's URL env var",
|
||||
providerID, info.NPM,
|
||||
)
|
||||
}
|
||||
|
||||
if strings.Contains(apiURL, "${") {
|
||||
resolved, err := resolveTemplatedAPIURL(apiURL, info)
|
||||
if err != nil {
|
||||
return apiURL, err
|
||||
}
|
||||
return resolved, nil
|
||||
}
|
||||
return apiURL, nil
|
||||
}
|
||||
|
||||
// createGoogleVertexProvider creates a Google Gemini provider that targets the
|
||||
// Vertex AI backend (rather than the public generativelanguage.googleapis.com
|
||||
// endpoint). It requires the same project/region environment variables as
|
||||
// google-vertex-anthropic.
|
||||
func createGoogleVertexProvider(ctx context.Context, config *ProviderConfig, modelName string) (*ProviderResult, error) {
|
||||
projectID := firstNonEmpty(
|
||||
os.Getenv("GOOGLE_VERTEX_PROJECT"),
|
||||
os.Getenv("GOOGLE_CLOUD_PROJECT"),
|
||||
os.Getenv("GCLOUD_PROJECT"),
|
||||
os.Getenv("CLOUDSDK_CORE_PROJECT"),
|
||||
)
|
||||
if projectID == "" {
|
||||
return nil, fmt.Errorf(
|
||||
"google Vertex project ID not provided, set GOOGLE_VERTEX_PROJECT, " +
|
||||
"GOOGLE_CLOUD_PROJECT, or GCLOUD_PROJECT environment variable",
|
||||
)
|
||||
}
|
||||
|
||||
region := firstNonEmpty(
|
||||
os.Getenv("GOOGLE_VERTEX_LOCATION"),
|
||||
os.Getenv("CLOUD_ML_REGION"),
|
||||
)
|
||||
if region == "" {
|
||||
region = "global"
|
||||
}
|
||||
|
||||
opts := []google.Option{
|
||||
google.WithVertex(projectID, region),
|
||||
google.WithName("google-vertex"),
|
||||
}
|
||||
|
||||
if config.TLSSkipVerify {
|
||||
opts = append(opts, google.WithHTTPClient(createHTTPClientWithTLSConfig(true)))
|
||||
}
|
||||
|
||||
provider, err := google.New(opts...)
|
||||
if err != nil {
|
||||
return nil, wrapProviderErr("Google Vertex", "provider", err)
|
||||
}
|
||||
|
||||
model, err := provider.LanguageModel(ctx, modelName)
|
||||
if err != nil {
|
||||
return nil, wrapProviderErr("Google Vertex", "model", err)
|
||||
}
|
||||
|
||||
return &ProviderResult{Model: model}, nil
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestSDKDefaultBaseURL_CoversAllWireMappedPackages enforces the invariant
|
||||
// that every npm package recognised by the auto-router has a corresponding
|
||||
// default base URL — otherwise a provider that omits its `api` field in the
|
||||
// registry would silently fail to route at runtime.
|
||||
func TestSDKDefaultBaseURL_CoversAllWireMappedPackages(t *testing.T) {
|
||||
for npm := range npmToWireProtocol {
|
||||
// @ai-sdk/openai-compatible is a wire family, not a single SDK with
|
||||
// a default URL — providers using it always supply their own `api`.
|
||||
if npm == "@ai-sdk/openai-compatible" {
|
||||
continue
|
||||
}
|
||||
if _, ok := sdkDefaultBaseURL[npm]; !ok {
|
||||
t.Errorf("npm %q is in npmToWireProtocol but has no sdkDefaultBaseURL entry — "+
|
||||
"providers using this npm with no `api` field cannot be routed", npm)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestSDKDefaultBaseURL_AllURLsAreAbsolute sanity-checks that every default
|
||||
// URL is a well-formed absolute https endpoint (catches typos in the table).
|
||||
func TestSDKDefaultBaseURL_AllURLsAreAbsolute(t *testing.T) {
|
||||
for npm, url := range sdkDefaultBaseURL {
|
||||
if !strings.HasPrefix(url, "https://") {
|
||||
t.Errorf("sdkDefaultBaseURL[%q] = %q is not an absolute https URL", npm, url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveProviderBaseURL_RegistryFirst verifies that the registry's `api`
|
||||
// field wins over any SDK default.
|
||||
func TestResolveProviderBaseURL_RegistryFirst(t *testing.T) {
|
||||
// xai is in the registry with no `api` field — its URL comes from the
|
||||
// SDK default. Use a synthetic registry-backed provider to test the
|
||||
// priority via the public registry instead.
|
||||
url, err := ResolveProviderBaseURL("openai")
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveProviderBaseURL(openai): %v", err)
|
||||
}
|
||||
if url != "https://api.openai.com/v1" {
|
||||
t.Errorf("openai URL = %q, want https://api.openai.com/v1", url)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveProviderBaseURL_SDKDefaultFallback verifies that providers
|
||||
// without an `api` field (groq, cerebras, xai, …) resolve to their SDK
|
||||
// hard-coded default URL.
|
||||
func TestResolveProviderBaseURL_SDKDefaultFallback(t *testing.T) {
|
||||
tests := map[string]string{
|
||||
"groq": "https://api.groq.com/openai/v1",
|
||||
"cerebras": "https://api.cerebras.ai/v1",
|
||||
"xai": "https://api.x.ai/v1",
|
||||
"mistral": "https://api.mistral.ai/v1",
|
||||
"perplexity": "https://api.perplexity.ai",
|
||||
"togetherai": "https://api.together.xyz/v1",
|
||||
"deepinfra": "https://api.deepinfra.com/v1/openai",
|
||||
"cohere": "https://api.cohere.com/compatibility/v1",
|
||||
"v0": "https://api.v0.dev/v1",
|
||||
"aihubmix": "https://aihubmix.com/v1",
|
||||
"venice": "https://api.venice.ai/api/v1",
|
||||
"openrouter": "https://openrouter.ai/api/v1",
|
||||
}
|
||||
for providerID, wantURL := range tests {
|
||||
t.Run(providerID, func(t *testing.T) {
|
||||
got, err := ResolveProviderBaseURL(providerID)
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveProviderBaseURL(%s): %v", providerID, err)
|
||||
}
|
||||
if got != wantURL {
|
||||
t.Errorf("%s URL = %q, want %q", providerID, got, wantURL)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveProviderBaseURL_TemplatedURL_MissingEnv verifies that providers
|
||||
// whose URL contains "${VAR}" placeholders surface a targeted error when the
|
||||
// environment variables are unset.
|
||||
func TestResolveProviderBaseURL_TemplatedURL_MissingEnv(t *testing.T) {
|
||||
// cloudflare-workers-ai's api URL contains ${CLOUDFLARE_ACCOUNT_ID}.
|
||||
// Ensure the variable is unset for this test.
|
||||
t.Setenv("CLOUDFLARE_ACCOUNT_ID", "")
|
||||
t.Setenv("CF_ACCOUNT_ID", "")
|
||||
|
||||
_, err := ResolveProviderBaseURL("cloudflare-workers-ai")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for unset CLOUDFLARE_ACCOUNT_ID, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "CLOUDFLARE_ACCOUNT_ID") {
|
||||
t.Errorf("error should name the missing env var, got: %v", err)
|
||||
}
|
||||
if !strings.Contains(err.Error(), "--provider-url") {
|
||||
t.Errorf("error should suggest --provider-url override, got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveProviderBaseURL_TemplatedURL_Resolved verifies env-var
|
||||
// substitution succeeds when the placeholder is set.
|
||||
func TestResolveProviderBaseURL_TemplatedURL_Resolved(t *testing.T) {
|
||||
t.Setenv("CLOUDFLARE_ACCOUNT_ID", "test-acct-123")
|
||||
got, err := ResolveProviderBaseURL("cloudflare-workers-ai")
|
||||
if err != nil {
|
||||
t.Fatalf("ResolveProviderBaseURL: %v", err)
|
||||
}
|
||||
if !strings.Contains(got, "test-acct-123") {
|
||||
t.Errorf("resolved URL %q should contain test-acct-123", got)
|
||||
}
|
||||
if strings.Contains(got, "${") {
|
||||
t.Errorf("resolved URL %q still contains template placeholder", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveProviderBaseURL_UnknownProvider verifies the not-in-registry error.
|
||||
func TestResolveProviderBaseURL_UnknownProvider(t *testing.T) {
|
||||
_, err := ResolveProviderBaseURL("does-not-exist")
|
||||
if err == nil {
|
||||
t.Fatal("expected error for unknown provider, got nil")
|
||||
}
|
||||
if !strings.Contains(err.Error(), "unknown provider") {
|
||||
t.Errorf("error should say 'unknown provider', got: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestAutoRouteProvider_SDKDefaultURLFallback verifies that providers whose
|
||||
// registry entry omits the `api` field (groq, mistral, xai, etc.) are still
|
||||
// auto-routed by falling back to the SDK's hard-coded default URL.
|
||||
func TestAutoRouteProvider_SDKDefaultURLFallback(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
npmPackage string
|
||||
wantInURL string
|
||||
}{
|
||||
{"groq", "@ai-sdk/groq", "groq.com"},
|
||||
{"cerebras", "@ai-sdk/cerebras", "cerebras.ai"},
|
||||
{"xai", "@ai-sdk/xai", "x.ai"},
|
||||
{"mistral", "@ai-sdk/mistral", "mistral.ai"},
|
||||
{"v0", "@ai-sdk/vercel", "v0.dev"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
reg := &ModelsRegistry{
|
||||
providers: map[string]ProviderInfo{
|
||||
"testfallback": {
|
||||
ID: "testfallback",
|
||||
Name: "Test Fallback",
|
||||
Env: []string{"TESTFALLBACK_API_KEY"},
|
||||
NPM: tt.npmPackage,
|
||||
// API intentionally omitted — must fall back to SDK default.
|
||||
Models: map[string]ModelInfo{
|
||||
"any-model": {ID: "any-model", Name: "any-model"},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
config := &ProviderConfig{ProviderAPIKey: "test-key"}
|
||||
|
||||
result, err := autoRouteProvider(context.Background(), config, "testfallback", "any-model", reg)
|
||||
if err != nil {
|
||||
t.Fatalf("autoRouteProvider returned error: %v", err)
|
||||
}
|
||||
if result == nil || result.Model == nil {
|
||||
t.Fatal("autoRouteProvider returned nil model")
|
||||
}
|
||||
// Verify the SDK default URL was picked up.
|
||||
if !strings.Contains(config.ProviderURL, tt.wantInURL) {
|
||||
t.Errorf("config.ProviderURL = %q, want substring %q (SDK default)",
|
||||
config.ProviderURL, tt.wantInURL)
|
||||
}
|
||||
// All these wrappers route through the openai-compat wire.
|
||||
gotType := reflect.TypeOf(result.Model).String()
|
||||
if gotType != "openai.languageModel" {
|
||||
t.Errorf("model type = %q, want openai.languageModel", gotType)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveTemplatedAPIURL_NoPlaceholders verifies that URLs without
|
||||
// placeholders are returned as-is (the caller keeps using the original).
|
||||
func TestResolveTemplatedAPIURL_NoPlaceholders(t *testing.T) {
|
||||
got, err := resolveTemplatedAPIURL("https://api.example.com/v1", &ProviderInfo{ID: "x"})
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if got != "" {
|
||||
t.Errorf("got %q, want empty string for URL with no placeholders", got)
|
||||
}
|
||||
}
|
||||
|
||||
// TestResolveTemplatedAPIURL_AltEnvVar verifies that the alternative env-var
|
||||
// names (e.g. CF_ACCOUNT_ID for CLOUDFLARE_ACCOUNT_ID) are honoured.
|
||||
func TestResolveTemplatedAPIURL_AltEnvVar(t *testing.T) {
|
||||
t.Setenv("CLOUDFLARE_ACCOUNT_ID", "")
|
||||
t.Setenv("CF_ACCOUNT_ID", "alt-name-123")
|
||||
|
||||
got, err := resolveTemplatedAPIURL(
|
||||
"https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1",
|
||||
&ProviderInfo{ID: "cloudflare-workers-ai"},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if !strings.Contains(got, "alt-name-123") {
|
||||
t.Errorf("resolved URL %q should have picked up CF_ACCOUNT_ID alternative", got)
|
||||
}
|
||||
}
|
||||
@@ -61,3 +61,23 @@ func CheckProviderReady(provider string) error {
|
||||
}
|
||||
return models.GetGlobalRegistry().ValidateEnvironment(provider, "")
|
||||
}
|
||||
|
||||
// ResolveProviderBaseURL returns the base API URL kit will use when talking to
|
||||
// the given provider, applying the same resolution order that CreateProvider
|
||||
// uses internally:
|
||||
//
|
||||
// 1. The provider's `api` field from the models.dev registry.
|
||||
// 2. The hard-coded default base URL of its npm SDK package (e.g.
|
||||
// @ai-sdk/groq → https://api.groq.com/openai/v1).
|
||||
// 3. Template substitution against the current process environment when the
|
||||
// URL contains "${VAR}" placeholders.
|
||||
//
|
||||
// Returns a non-nil error when the provider is unknown, when no URL can be
|
||||
// derived, or when a templated URL has unset placeholders.
|
||||
//
|
||||
// Use this from your SDK integration to surface the effective endpoint before
|
||||
// instantiating a Kit, or to validate that a provider is reachable without
|
||||
// running an actual request.
|
||||
func ResolveProviderBaseURL(providerID string) (string, error) {
|
||||
return models.ResolveProviderBaseURL(providerID)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user