diff --git a/.env.example b/.env.example index 8104063e..709d40c1 100644 --- a/.env.example +++ b/.env.example @@ -39,8 +39,9 @@ OPENROUTER_API_KEY=sk-or-v1-your-key # Option 4: Google Vertex AI (HIPAA compliant with BAA) # AI_PROVIDER=vertex -# GOOGLE_VERTEX_PROJECT=your-gcp-project-id -# GOOGLE_VERTEX_LOCATION=us-central1 +# Google models (Gemini and friends) are reached through LiteLLM, not the +# Google SDK — that dependency was removed. Configure them on the gateway +# and select them by their LiteLLM model id. # GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json # (Or use default credentials if running on GCE/GKE/Cloud Run) # diff --git a/package-lock.json b/package-lock.json index 68342546..767e38e4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,8 +55,7 @@ "@aws-sdk/client-bedrock-runtime": "^3.700.0", "@aws-sdk/client-s3": "^3.700.0", "@aws-sdk/client-transcribe-streaming": "^3.1017.0", - "@aws-sdk/s3-request-presigner": "^3.700.0", - "@google-cloud/vertexai": "^1.9.0" + "@aws-sdk/s3-request-presigner": "^3.700.0" } }, "node_modules/@asamuzakjp/css-color": { @@ -1577,131 +1576,6 @@ } } }, - "node_modules/@google-cloud/vertexai": { - "version": "1.10.3", - "resolved": "https://registry.npmjs.org/@google-cloud/vertexai/-/vertexai-1.10.3.tgz", - "integrity": "sha512-YcEaYPyUVVRz4adNiR4jQQeq/XSOUwH6SERL7NGdZlCXKY+7BofFQpcd71HgdSkzTgERcVQ3TZquNwXNqlTQXQ==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@google/genai": "^1.45.0", - "google-auth-library": "^9.1.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@google/genai": { - "version": "1.47.0", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-1.47.0.tgz", - "integrity": "sha512-0VV7AaXm5rQu3oRHNZNEubRAOL2lv5u+YA72eWnDwcOx3B1jFRbvtgL4drRHlocRHOnludvr3xmbQGbR+/RQAQ==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "google-auth-library": "^10.3.0", - "p-retry": "^4.6.2", - "protobufjs": "^7.5.4", - "ws": "^8.18.0" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@modelcontextprotocol/sdk": "^1.25.2" - }, - "peerDependenciesMeta": { - "@modelcontextprotocol/sdk": { - "optional": true - } - } - }, - "node_modules/@google/genai/node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 12" - } - }, - "node_modules/@google/genai/node_modules/gaxios": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.4.tgz", - "integrity": "sha512-bTIgTsM2bWn3XklZISBTQX7ZSddGW+IO3bMdGaemHZ3tbqExMENHLx6kKZ/KlejgrMtj8q7wBItt51yegqalrA==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "node-fetch": "^3.3.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@google/genai/node_modules/gcp-metadata": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-8.1.2.tgz", - "integrity": "sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "gaxios": "^7.0.0", - "google-logging-utils": "^1.0.0", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@google/genai/node_modules/google-auth-library": { - "version": "10.6.2", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-10.6.2.tgz", - "integrity": "sha512-e27Z6EThmVNNvtYASwQxose/G57rkRuaRbQyxM2bvYLLX/GqWZ5chWq2EBoUchJbCc57eC9ArzO5wMsEmWftCw==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^7.1.4", - "gcp-metadata": "8.1.2", - "google-logging-utils": "1.1.3", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@google/genai/node_modules/google-logging-utils": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz", - "integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@google/genai/node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "license": "MIT", - "optional": true, - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/@img/colour": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", @@ -2308,72 +2182,6 @@ "node": ">=10" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.5.tgz", - "integrity": "sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.1.tgz", - "integrity": "sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.1.tgz", - "integrity": "sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.1" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause", - "optional": true - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.2.tgz", - "integrity": "sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==", - "license": "BSD-3-Clause", - "optional": true - }, "node_modules/@redis/bloom": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", @@ -3644,13 +3452,6 @@ "form-data": "^4.0.4" } }, - "node_modules/@types/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==", - "license": "MIT", - "optional": true - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -3692,16 +3493,6 @@ "node": ">= 0.6" } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 14" - } - }, "node_modules/agentkeepalive": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", @@ -3897,16 +3688,6 @@ "require-from-string": "^2.0.2" } }, - "node_modules/bignumber.js": { - "version": "9.3.1", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz", - "integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==", - "license": "MIT", - "optional": true, - "engines": { - "node": "*" - } - }, "node_modules/bintrees": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz", @@ -4616,47 +4397,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "license": "MIT", - "optional": true - }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "optional": true, - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fetch-blob/node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 8" - } - }, "node_modules/finalhandler": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.2.tgz", @@ -4759,19 +4499,6 @@ "node": ">= 12.20" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "license": "MIT", - "optional": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -4799,38 +4526,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gaxios": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", - "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/gcp-metadata": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", - "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "gaxios": "^6.1.1", - "google-logging-utils": "^0.0.2", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, "node_modules/generic-pool": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", @@ -4910,34 +4605,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/google-auth-library": { - "version": "9.15.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", - "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^6.1.1", - "gcp-metadata": "^6.1.0", - "gtoken": "^7.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/google-logging-utils": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", - "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", - "license": "Apache-2.0", - "optional": true, - "engines": { - "node": ">=14" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -4950,20 +4617,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gtoken": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", - "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", - "license": "MIT", - "optional": true, - "dependencies": { - "gaxios": "^6.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -5054,45 +4707,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "optional": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/https-proxy-agent/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT", - "optional": true - }, "node_modules/humanize-ms": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", @@ -5151,19 +4765,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -5311,16 +4912,6 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, "node_modules/jsonwebtoken": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", @@ -5492,13 +5083,6 @@ "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0", - "optional": true - }, "node_modules/lop": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/lop/-/lop-0.4.2.tgz", @@ -6094,20 +5678,6 @@ "node": ">=8" } }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -6619,30 +6189,6 @@ "prosemirror-transform": "^1.1.0" } }, - "node_modules/protobufjs": { - "version": "7.6.6", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.6.tgz", - "integrity": "sha512-dYDWdjSl5RNb7SgPxGQcRU+GtvP7s2fpkrY0r432PcOIaZ0/rBcxEZnQN67iJhFuQiVw754JDoPruPCNdGsbjg==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.5", - "@protobufjs/eventemitter": "^1.1.1", - "@protobufjs/fetch": "^1.1.1", - "@protobufjs/float": "^1.0.2", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.1", - "@types/node": ">=13.7.0", - "long": "^5.3.2" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -6779,16 +6325,6 @@ "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, - "node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/rope-sequence": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz", @@ -7322,20 +6858,6 @@ "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "optional": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -7446,6 +6968,7 @@ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", "license": "MIT", "optional": true, + "peer": true, "engines": { "node": ">=10.0.0" }, diff --git a/package.json b/package.json index 13e01ed6..7a5024df 100644 --- a/package.json +++ b/package.json @@ -57,8 +57,7 @@ "@aws-sdk/client-bedrock-runtime": "^3.700.0", "@aws-sdk/client-s3": "^3.700.0", "@aws-sdk/client-transcribe-streaming": "^3.1017.0", - "@aws-sdk/s3-request-presigner": "^3.700.0", - "@google-cloud/vertexai": "^1.9.0" + "@aws-sdk/s3-request-presigner": "^3.700.0" }, "devDependencies": { "jsdom": "^29.0.2" diff --git a/server.js b/server.js index 4d88ed2d..351c4577 100644 --- a/server.js +++ b/server.js @@ -290,7 +290,6 @@ app.get('/api/health/detailed', _hcAuth, _hcAdmin, (req, res) => { openrouter: process.env.OPENROUTER_API_KEY ? 'configured' : 'missing', bedrock: process.env.AWS_BEDROCK_REGION ? 'configured' : 'not configured', azure: process.env.AZURE_OPENAI_ENDPOINT ? 'configured' : 'not configured', - vertex: process.env.GOOGLE_VERTEX_PROJECT ? 'configured' : 'not configured', litellm: process.env.LITELLM_API_BASE ? 'configured' : 'not configured', whisper: process.env.OPENAI_API_KEY ? 'configured' : 'missing', tts: process.env.LITELLM_API_BASE ? 'litellm' : (process.env.ELEVENLABS_API_KEY ? 'elevenlabs' : 'none') diff --git a/src/routes/adminConfig.js b/src/routes/adminConfig.js index b4c04883..1730393c 100644 --- a/src/routes/adminConfig.js +++ b/src/routes/adminConfig.js @@ -321,12 +321,11 @@ router.delete('/config/smtp', async function(req, res) { // ── GET models config ──────────────────────────────────────────────────── router.get('/config/models', async function(req, res) { try { - var { OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS, VERTEX_MODELS, activeProvider } = require('../utils/models'); + var { OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS, activeProvider } = require('../utils/models'); var providerModels; switch (activeProvider) { case 'bedrock': providerModels = BEDROCK_MODELS; break; case 'azure': providerModels = AZURE_MODELS; break; - case 'vertex': providerModels = VERTEX_MODELS; break; case 'litellm': providerModels = []; break; // LiteLLM: no built-ins — use discover default: providerModels = OPENROUTER_MODELS; } @@ -409,8 +408,8 @@ router.post('/config/models/custom', async function(req, res) { } // Check if model ID conflicts with a built-in model (all providers) - var { OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS, VERTEX_MODELS } = require('../utils/models'); - var allBuiltIn = [].concat(OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS, VERTEX_MODELS); + var { OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS } = require('../utils/models'); + var allBuiltIn = [].concat(OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS); if (allBuiltIn.find(function(m) { return m.id === trimmedId; })) { return res.status(400).json({ error: 'Model ID conflicts with a built-in model. Use the toggle to enable/disable built-in models.' }); } diff --git a/src/utils/ai.js b/src/utils/ai.js index 13d404c2..81cd75e6 100644 --- a/src/utils/ai.js +++ b/src/utils/ai.js @@ -72,25 +72,6 @@ if (process.env.AZURE_OPENAI_ENDPOINT) { } } -// ============================================================ -// GOOGLE VERTEX AI CLIENT (optional, HIPAA compliant with BAA) -// ============================================================ -var vertexClient = null; -if (process.env.GOOGLE_VERTEX_PROJECT) { - try { - var VertexAI = require('@google-cloud/vertexai'); - vertexClient = new VertexAI.VertexAI({ - project: process.env.GOOGLE_VERTEX_PROJECT, - location: process.env.GOOGLE_VERTEX_LOCATION || 'us-central1' - }); - activeProvider = 'vertex'; - console.log('✅ Google Vertex AI: configured (project: ' + process.env.GOOGLE_VERTEX_PROJECT + ', location: ' + (process.env.GOOGLE_VERTEX_LOCATION || 'us-central1') + ')'); - } catch (e) { - console.log('⚠️ Google Vertex AI: SDK not installed. Install with: npm install @google-cloud/vertexai'); - console.log('⚠️ Falling back to OpenRouter'); - activeProvider = 'openrouter'; - } -} // ============================================================ // LITELLM CLIENT (optional — OpenAI-compatible proxy) @@ -125,8 +106,12 @@ if (activeProvider === 'azure' && !azureClient) { console.log('⚠️ Azure selected but not available. Falling back to OpenRouter.'); activeProvider = 'openrouter'; } -if (activeProvider === 'vertex' && !vertexClient) { - console.log('⚠️ Vertex AI selected but not available. Falling back to OpenRouter.'); +// Vertex is reached through LiteLLM now, not through the Google SDK, which was +// removed along with the two advisories it carried. AI_PROVIDER=vertex is +// therefore not a thing this app can be; point the operator at the gateway +// rather than silently doing something else. +if (activeProvider === 'vertex') { + console.log('⚠️ AI_PROVIDER=vertex is no longer supported directly. Configure the model through LiteLLM instead. Falling back to OpenRouter.'); activeProvider = 'openrouter'; } if (activeProvider === 'litellm' && !litellmClient) { @@ -367,66 +352,6 @@ async function callBedrock(messages, model, temperature, maxTokens) { } } -// ============================================================ -// CALL GOOGLE VERTEX AI -// Uses the Gemini generateContent API -// ============================================================ -async function callVertex(messages, model, temperature, maxTokens) { - if (!vertexClient) throw new Error('Google Vertex AI not configured'); - - // Map model ID to Vertex model name - var { getVertexModelId } = require('./models'); - var vertexModelId = getVertexModelId(model); - - var generativeModel = vertexClient.getGenerativeModel({ - model: vertexModelId, - generationConfig: { - temperature: temperature, - maxOutputTokens: maxTokens, - }, - }); - - // Convert OpenAI-style messages to Vertex AI format - var systemInstruction = ''; - var contents = []; - messages.forEach(function(m) { - if (m.role === 'system') { - systemInstruction += (systemInstruction ? '\n' : '') + m.content; - } else { - contents.push({ - role: m.role === 'assistant' ? 'model' : 'user', - parts: [{ text: m.content }] - }); - } - }); - - var request = { contents: contents }; - if (systemInstruction) { - request.systemInstruction = { parts: [{ text: systemInstruction }] }; - } - - var result = await generativeModel.generateContent(request); - var response = result.response; - - var textContent = ''; - if (response.candidates && response.candidates[0] && response.candidates[0].content) { - response.candidates[0].content.parts.forEach(function(part) { - if (part.text) textContent += part.text; - }); - } - - return { - success: true, - content: textContent, - finishReason: normalizeFinishReason(response.candidates && response.candidates[0] && response.candidates[0].finishReason), - model: vertexModelId, - provider: 'vertex', - usage: response.usageMetadata ? { - prompt_tokens: response.usageMetadata.promptTokenCount || 0, - completion_tokens: response.usageMetadata.candidatesTokenCount || 0 - } : null - }; -} // ============================================================ // CALL LITELLM (OpenAI-compatible proxy) @@ -570,8 +495,6 @@ async function callAI(messages, options) { result = await callBedrock(messages, model, temperature, maxTokens); } else if (activeProvider === 'azure' && azureClient) { result = await callAzure(messages, model, temperature, maxTokens, generation); - } else if (activeProvider === 'vertex' && vertexClient) { - result = await callVertex(messages, model, temperature, maxTokens); } else if (activeProvider === 'litellm' && litellmClient) { result = await callLiteLLM(messages, model, temperature, maxTokens, generation); } else if (openrouter) { @@ -678,13 +601,6 @@ async function discoverModels() { } } - if (activeProvider === 'vertex' && vertexClient) { - // Vertex AI doesn't have a simple list API, return known Gemini models - var { VERTEX_MODELS } = require('./models'); - VERTEX_MODELS.forEach(function(m) { - discovered.push(Object.assign({}, m, { source: 'vertex-builtin' })); - }); - } if (activeProvider === 'openrouter' && openrouter) { try { @@ -766,4 +682,4 @@ async function discoverModels() { return discovered; } -module.exports = { callAI, callAIStream, activeProvider, discoverModels, vertexClient, litellmClient, applyImageAttachments }; +module.exports = { callAI, callAIStream, activeProvider, discoverModels, litellmClient, applyImageAttachments }; diff --git a/src/utils/models.js b/src/utils/models.js index 409db7f4..d14c3979 100644 --- a/src/utils/models.js +++ b/src/utils/models.js @@ -1,6 +1,7 @@ // ============================================================ // MODELS.JS — Provider-aware model list -// Supports: OpenRouter, AWS Bedrock, Azure OpenAI, Google Vertex AI, LiteLLM +// Supports: OpenRouter, AWS Bedrock, Azure OpenAI, LiteLLM. +// Vertex and anything else Google is reached through LiteLLM, not directly. // ============================================================ var activeProvider = process.env.AI_PROVIDER || (process.env.LITELLM_API_BASE ? 'litellm' : 'openrouter'); @@ -88,27 +89,6 @@ var AZURE_MODELS = [ deploymentNote: 'Set AZURE_DEPLOYMENT_NAME in .env' } ]; -// ============================================================ -// GOOGLE VERTEX AI MODELS -// vertexId = the model name used in Vertex AI API calls -// ============================================================ -var VERTEX_MODELS = [ - { id: 'gemini-2.5-flash', name: 'Gemini 2.5 Flash', - vertexId: 'gemini-2.5-flash-preview-05-20' }, - { id: 'gemini-2.5-pro', name: 'Gemini 2.5 Pro', - vertexId: 'gemini-2.5-pro-preview-05-06' }, - { id: 'gemini-2.0-flash', name: 'Gemini 2.0 Flash', - vertexId: 'gemini-2.0-flash' }, - { id: 'gemini-2.0-flash-lite', name: 'Gemini 2.0 Flash Lite', - vertexId: 'gemini-2.0-flash-lite' }, - { id: 'gemini-1.5-pro', name: 'Gemini 1.5 Pro', - vertexId: 'gemini-1.5-pro-002' }, - { id: 'gemini-1.5-flash', name: 'Gemini 1.5 Flash', - vertexId: 'gemini-1.5-flash-002' }, - { id: 'llama-3.1-405b@vertex', name: 'Llama 3.1 405B (Vertex)', - vertexId: 'meta/llama-3.1-405b-instruct-maas' }, -]; - // LiteLLM has NO built-in models — everything is discovered from the proxy via admin panel. // This array is intentionally empty. Do not add models here. var LITELLM_MODELS = []; @@ -121,7 +101,6 @@ function getAvailableModels() { return !m.regions || m.regions.indexOf(region) !== -1; }); case 'azure': return AZURE_MODELS; - case 'vertex': return VERTEX_MODELS; case 'litellm': return LITELLM_MODELS; case 'openrouter': default: return OPENROUTER_MODELS; @@ -132,7 +111,6 @@ function getDefaultModel() { switch (activeProvider) { case 'bedrock': return 'amazon/nova-pro'; case 'azure': return process.env.AZURE_DEPLOYMENT_NAME || 'gpt-4o-mini'; - case 'vertex': return 'gemini-2.5-flash'; case 'litellm': return process.env.LITELLM_DEFAULT_MODEL || process.env.OPENAI_MODEL || ''; // OpenAI-compatible base: set admin default or env. case 'openrouter': default: return 'google/gemini-2.5-flash'; @@ -143,7 +121,6 @@ function getFallbackModel() { switch (activeProvider) { case 'bedrock': return 'amazon/nova-lite'; case 'azure': return process.env.AZURE_DEPLOYMENT_NAME || 'gpt-4o-mini'; - case 'vertex': return 'gemini-2.0-flash'; case 'litellm': return process.env.LITELLM_FALLBACK_MODEL || ''; // No implicit cross-provider fallback. case 'openrouter': default: return 'deepseek/deepseek-chat-v3-0324'; @@ -160,10 +137,6 @@ function getBedrockMaxOut(modelId) { return found && found.maxOut ? found.maxOut : null; } -function getVertexModelId(modelId) { - var found = VERTEX_MODELS.find(function(m) { return m.id === modelId; }); - return found ? found.vertexId : modelId; -} var AVAILABLE_MODELS = getAvailableModels(); var DEFAULT_MODEL = getDefaultModel(); @@ -233,7 +206,6 @@ module.exports = { OPENROUTER_MODELS, BEDROCK_MODELS, AZURE_MODELS, - VERTEX_MODELS, LITELLM_MODELS, getAvailableModels, getAvailableModelsWithOverrides, @@ -245,6 +217,5 @@ module.exports = { getFallbackModel, getBedrockModelId, getBedrockMaxOut, - getVertexModelId, activeProvider }; diff --git a/test/assistant-image-attachments.test.js b/test/assistant-image-attachments.test.js index a4044e08..dd44031c 100644 --- a/test/assistant-image-attachments.test.js +++ b/test/assistant-image-attachments.test.js @@ -233,9 +233,6 @@ test('legacy direct provider adapters refuse image attachments with 400 before c '@aws-sdk/client-bedrock-runtime': { InvokeModelCommand, ConverseCommand, BedrockRuntimeClient: class { async send(command) { sdkCalls.push(command); return { body: Buffer.from('{}') }; } } - }, - '@google-cloud/vertexai': { - VertexAI: class { getGenerativeModel() { return { async generateContent(request) { sdkCalls.push(request); return { response: { candidates: [] } }; } }; } } } }; const module = { exports: {} }; @@ -254,13 +251,16 @@ test('legacy direct provider adapters refuse image attachments with 400 before c await assert.rejects(module.exports.callAIStream(messages, { model: 'anthropic.claude-synthetic', images: [png] }, () => {}), error => error.statusCode === 400); assert.equal(sdkCalls.length, 0, 'refused before any provider contact'); + // AI_PROVIDER=vertex used to select a direct Google SDK adapter. That adapter + // and its dependency are gone — Google models are reached through LiteLLM now — + // so asking for it must fall back rather than half-configure something. const vertexModule = { exports: {} }; vm.runInNewContext(read('src/utils/ai.js'), { module: vertexModule, exports: vertexModule.exports, console: quiet, TextDecoder, process: { env: { AI_PROVIDER: 'vertex', GOOGLE_VERTEX_PROJECT: 'synthetic' } }, require(name) { assert.ok(Object.hasOwn(mocks, name), 'Unexpected adapter import: ' + name); return mocks[name]; } }); - await assert.rejects(vertexModule.exports.callAI(messages, { model: 'google/gemini-2.5-flash', images: [png] }), error => error.statusCode === 400); + assert.equal(vertexModule.exports.activeProvider, 'openrouter', 'vertex is no longer selectable'); assert.equal(sdkCalls.length, 0); }); diff --git a/test/clinical-conversation.test.js b/test/clinical-conversation.test.js index 85a3fab7..af583e63 100644 --- a/test/clinical-conversation.test.js +++ b/test/clinical-conversation.test.js @@ -315,16 +315,6 @@ function directAdapter(provider, mode, reason) { return { output: { message: { content: [{ text: 'Synthetic handoff.' }] } }, stopReason: reason }; } } - }, - '@google-cloud/vertexai': { - VertexAI: class { - getGenerativeModel() { - return { async generateContent(request) { - sdkCalls.push(request); - return { response: { candidates: [{ content: { parts: [{ text: 'Synthetic handoff.' }] }, finishReason: reason }] } }; - } }; - } - } } }; const module = { exports: {} }; @@ -342,8 +332,7 @@ function directAdapter(provider, mode, reason) { test('actual direct AI adapters propagate completion status without any route (fake SDK only)', async () => { for (const [provider, mode, model] of [ ['bedrock', 'invoke', 'anthropic.claude-synthetic'], - ['bedrock', 'converse', 'amazon/nova-lite'], - ['vertex', 'vertex', 'google/gemini-2.5-flash'] + ['bedrock', 'converse', 'amazon/nova-lite'] ]) { for (const [reason, normalized] of [ ['max_tokens', 'length'], ['MAX_TOKENS', 'length'],