@local-labs-jpollock/local-addon-nexus-ai 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/common/constants.d.ts +1 -0
- package/lib/common/constants.d.ts.map +1 -1
- package/lib/common/constants.js +1 -0
- package/lib/common/constants.js.map +1 -1
- package/lib/main/ai-gateway/AIGatewayRoutes.d.ts +20 -3
- package/lib/main/ai-gateway/AIGatewayRoutes.d.ts.map +1 -1
- package/lib/main/ai-gateway/AIGatewayRoutes.js +282 -99
- package/lib/main/ai-gateway/AIGatewayRoutes.js.map +1 -1
- package/lib/main/ai-gateway/anthropic-client.d.ts +4 -4
- package/lib/main/ai-gateway/anthropic-client.js +11 -11
- package/lib/main/ai-gateway/anthropic-client.js.map +1 -1
- package/lib/main/ai-gateway/google-client.d.ts +48 -0
- package/lib/main/ai-gateway/google-client.d.ts.map +1 -0
- package/lib/main/ai-gateway/google-client.js +270 -0
- package/lib/main/ai-gateway/google-client.js.map +1 -0
- package/lib/main/ai-gateway/image-client.d.ts +46 -0
- package/lib/main/ai-gateway/image-client.d.ts.map +1 -0
- package/lib/main/ai-gateway/image-client.js +140 -0
- package/lib/main/ai-gateway/image-client.js.map +1 -0
- package/lib/main/ai-gateway/mu-plugin-template.d.ts.map +1 -1
- package/lib/main/ai-gateway/mu-plugin-template.js +30 -0
- package/lib/main/ai-gateway/mu-plugin-template.js.map +1 -1
- package/lib/main/ai-gateway/openai-client.d.ts.map +1 -1
- package/lib/main/ai-gateway/openai-client.js +20 -8
- package/lib/main/ai-gateway/openai-client.js.map +1 -1
- package/lib/main/chat/providers/google.d.ts.map +1 -1
- package/lib/main/chat/providers/google.js +1 -1
- package/lib/main/chat/providers/google.js.map +1 -1
- package/lib/main/chat/providers/openai.d.ts.map +1 -1
- package/lib/main/chat/providers/openai.js +3 -2
- package/lib/main/chat/providers/openai.js.map +1 -1
- package/lib/main/events/HttpEventInterface.d.ts.map +1 -1
- package/lib/main/events/HttpEventInterface.js +23 -1
- package/lib/main/events/HttpEventInterface.js.map +1 -1
- package/lib/main/ipc-handlers.d.ts.map +1 -1
- package/lib/main/ipc-handlers.js +7 -2
- package/lib/main/ipc-handlers.js.map +1 -1
- package/lib/renderer/components/AIGatewayUsagePanel.d.ts +2 -0
- package/lib/renderer/components/AIGatewayUsagePanel.d.ts.map +1 -1
- package/lib/renderer/components/AIGatewayUsagePanel.js +16 -1
- package/lib/renderer/components/AIGatewayUsagePanel.js.map +1 -1
- package/lib/renderer/components/NexusPreferences.d.ts.map +1 -1
- package/lib/renderer/components/NexusPreferences.js +11 -1
- package/lib/renderer/components/NexusPreferences.js.map +1 -1
- package/lib/renderer/components/NexusSiteTab.d.ts.map +1 -1
- package/lib/renderer/components/NexusSiteTab.js +10 -2
- package/lib/renderer/components/NexusSiteTab.js.map +1 -1
- package/lib/renderer/components/SidebarSearchPanel.d.ts +7 -1
- package/lib/renderer/components/SidebarSearchPanel.d.ts.map +1 -1
- package/lib/renderer/components/SidebarSearchPanel.js +49 -7
- package/lib/renderer/components/SidebarSearchPanel.js.map +1 -1
- package/lib/wp-plugins/ai-provider-for-local-gateway/plugin.php +3 -2
- package/lib/wp-plugins/ai-provider-for-local-gateway/src/Metadata/LocalGatewayModelMetadataDirectory.php +88 -60
- package/lib/wp-plugins/ai-provider-for-local-gateway/src/Models/LocalGatewayImageGenerationModel.php +170 -0
- package/lib/wp-plugins/ai-provider-for-local-gateway/src/Provider/LocalGatewayProvider.php +4 -0
- package/package.json +2 -1
- package/wp-plugins/ai-provider-for-local-gateway/plugin.php +3 -2
- package/wp-plugins/ai-provider-for-local-gateway/src/Metadata/LocalGatewayModelMetadataDirectory.php +88 -60
- package/wp-plugins/ai-provider-for-local-gateway/src/Models/LocalGatewayImageGenerationModel.php +170 -0
- package/wp-plugins/ai-provider-for-local-gateway/src/Provider/LocalGatewayProvider.php +4 -0
|
@@ -84,6 +84,7 @@ export declare const IPC_CHANNELS: {
|
|
|
84
84
|
readonly AI_GATEWAY_GET_RATE_LIMIT: "nexus-ai:ai-gateway:get-rate-limit";
|
|
85
85
|
readonly AI_GATEWAY_SET_RATE_LIMIT: "nexus-ai:ai-gateway:set-rate-limit";
|
|
86
86
|
readonly AI_GATEWAY_CHECK_RATE_LIMIT: "nexus-ai:ai-gateway:check-rate-limit";
|
|
87
|
+
readonly AI_GATEWAY_USAGE_UPDATED: "nexus-ai:ai-gateway:usage-updated";
|
|
87
88
|
readonly AI_CONTEXT_GENERATE: "nexus-ai:ai-context:generate";
|
|
88
89
|
readonly AI_CONTEXT_GET_STATUS: "nexus-ai:ai-context:get-status";
|
|
89
90
|
readonly WPE_SYNC_ALL: "nexus-ai:wpe:sync-all";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,YAAY,aAAa,CAAC;AAMvC,eAAO,MAAM,YAAY
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,YAAY,CAAC;AACpC,eAAO,MAAM,YAAY,aAAa,CAAC;AAMvC,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0Jf,CAAC;AAMX,eAAO,MAAM,SAAS;;;;;;CAMZ,CAAC;AAEX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAMX,eAAO,MAAM,oBAAoB,QAAQ,CAAC;AAC1C,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AACxC,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,wBAAwB,sCAAsC,CAAC;AAE5E,eAAO,MAAM,cAAc;;;;;;;;CAQjB,CAAC;AAMX,eAAO,MAAM,YAAY;;;;;;;;;;;CAWf,CAAC;AAMX,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,aAAa,qBAAqB,CAAC;AAChD,eAAO,MAAM,iBAAiB,UAAU,CAAC;AAMzC,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,oBAAoB,eAAe,CAAC;AACjD,eAAO,MAAM,oBAAoB,cAAc,CAAC;AAChD,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAMjD,0CAA0C;AAC1C,eAAO,MAAM,mBAAmB,UA2B/B,CAAC;AAEF,2CAA2C;AAC3C,eAAO,MAAM,eAAe,MAAM,CAAC;AAMnC,eAAO,MAAM,eAAe,2BAA2B,CAAC;AACxD,eAAO,MAAM,uBAAuB,QAAS,CAAC;AAM9C,eAAO,MAAM,aAAa;;;CAGhB,CAAC"}
|
package/lib/common/constants.js
CHANGED
|
@@ -107,6 +107,7 @@ exports.IPC_CHANNELS = {
|
|
|
107
107
|
AI_GATEWAY_GET_RATE_LIMIT: `${exports.ADDON_PREFIX}:ai-gateway:get-rate-limit`,
|
|
108
108
|
AI_GATEWAY_SET_RATE_LIMIT: `${exports.ADDON_PREFIX}:ai-gateway:set-rate-limit`,
|
|
109
109
|
AI_GATEWAY_CHECK_RATE_LIMIT: `${exports.ADDON_PREFIX}:ai-gateway:check-rate-limit`,
|
|
110
|
+
AI_GATEWAY_USAGE_UPDATED: `${exports.ADDON_PREFIX}:ai-gateway:usage-updated`,
|
|
110
111
|
// AI Context File Generation
|
|
111
112
|
AI_CONTEXT_GENERATE: `${exports.ADDON_PREFIX}:ai-context:generate`,
|
|
112
113
|
AI_CONTEXT_GET_STATUS: `${exports.ADDON_PREFIX}:ai-context:get-status`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG,SAAS,CAAC;AACvB,QAAA,YAAY,GAAG,UAAU,CAAC;AAEvC,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAEjE,QAAA,YAAY,GAAG;IAC1B,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAC1D,UAAU,EAAE,GAAG,oBAAY,aAAa;IACxC,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,MAAM,EAAE,GAAG,oBAAY,SAAS;IAChC,UAAU,EAAE,GAAG,oBAAY,aAAa;IACxC,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAElD,WAAW;IACX,QAAQ,EAAE,GAAG,oBAAY,WAAW;IACpC,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IACxD,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IACxD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,UAAU,EAAE,GAAG,oBAAY,aAAa;IAExC,OAAO;IACP,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB;IACtD,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,UAAU,EAAE,GAAG,oBAAY,aAAa;IAExC,sBAAsB;IACtB,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,UAAU,EAAE,GAAG,oBAAY,aAAa;IACxC,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IAExD,yCAAyC;IACzC,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAC1D,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IACxD,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAClD,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAE1D,gCAAgC;IAChC,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IACxD,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,qBAAqB,EAAE,GAAG,oBAAY,wBAAwB;IAC9D,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,WAAW,EAAE,GAAG,oBAAY,cAAc;IAE1C,6BAA6B;IAC7B,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAE9C,yBAAyB;IACzB,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAClD,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IAExD,2BAA2B;IAC3B,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IACpD,sBAAsB,EAAE,GAAG,oBAAY,yBAAyB;IAEhE,0BAA0B;IAC1B,kBAAkB,EAAE,GAAG,oBAAY,qBAAqB;IAExD,6BAA6B;IAC7B,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAC5D,0BAA0B,EAAE,GAAG,oBAAY,0BAA0B;IAErE,uBAAuB;IACvB,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,iBAAiB,EAAE,GAAG,oBAAY,gBAAgB;IAClD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,eAAe,EAAE,GAAG,oBAAY,cAAc;IAE9C,6CAA6C;IAC7C,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB;IACtD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAEhD,qCAAqC;IACrC,uBAAuB,EAAE,GAAG,oBAAY,0BAA0B;IAClE,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB;IACtD,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAE5D,iBAAiB;IACjB,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAC1D,qBAAqB,EAAE,GAAG,oBAAY,wBAAwB;IAC9D,wBAAwB,EAAE,GAAG,oBAAY,2BAA2B;IAEpE,aAAa;IACb,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAEhD,qCAAqC;IACrC,iBAAiB,EAAE,GAAG,oBAAY,eAAe;IACjD,qBAAqB,EAAE,GAAG,oBAAY,mBAAmB;IAEzD,sCAAsC;IACtC,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAC5D,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAC1D,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAC5D,sBAAsB,EAAE,GAAG,oBAAY,yBAAyB;IAChE,yBAAyB,EAAE,GAAG,oBAAY,4BAA4B;IACtE,yBAAyB,EAAE,GAAG,oBAAY,4BAA4B;IACtE,2BAA2B,EAAE,GAAG,oBAAY,8BAA8B;IAC1E,wBAAwB,EAAE,GAAG,oBAAY,2BAA2B;IAEpE,6BAA6B;IAC7B,mBAAmB,EAAE,GAAG,oBAAY,sBAAsB;IAC1D,qBAAqB,EAAE,GAAG,oBAAY,wBAAwB;IAE9D,0BAA0B;IAC1B,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,YAAY,EAAE,GAAG,oBAAY,eAAe;IAC5C,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAClD,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,sBAAsB,EAAE,GAAG,oBAAY,iCAAiC;IACxE,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,iBAAiB,EAAE,GAAG,oBAAY,yBAAyB;IAC3D,sBAAsB,EAAE,GAAG,oBAAY,6BAA6B;IACpE,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAClD,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAC5D,oBAAoB,EAAE,GAAG,oBAAY,uBAAuB;IAC5D,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB;IACtD,eAAe,EAAE,GAAG,oBAAY,kBAAkB;IAClD,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB;IAEtD,2DAA2D;IAC3D,uBAAuB,EAAE,GAAG,oBAAY,0BAA0B;IAClE,uBAAuB,EAAE,GAAG,oBAAY,0BAA0B;IAClE,yBAAyB,EAAE,GAAG,oBAAY,4BAA4B;IACtE,8BAA8B,EAAE,GAAG,oBAAY,iCAAiC;IAEhF,mBAAmB;IACnB,YAAY,EAAE,GAAG,oBAAY,UAAU;IACvC,WAAW,EAAE,GAAG,oBAAY,cAAc;IAC1C,gBAAgB,EAAE,GAAG,oBAAY,mBAAmB;IAEpD,0EAA0E;IAC1E,eAAe,EAAE,GAAG,oBAAY,kBAAkB;CAC1C,CAAC;AAEX,8EAA8E;AAC9E,KAAK;AACL,8EAA8E;AAEjE,QAAA,SAAS,GAAG;IACvB,SAAS,EAAE,SAAS;IACpB,cAAc,EAAE,SAAS;IACzB,aAAa,EAAE,MAAM;IACrB,YAAY,EAAE,SAAS;IACvB,cAAc,EAAE,SAAS;CACjB,CAAC;AAEE,QAAA,cAAc,GAAG;IAC5B,kBAAkB,EAAE,KAAM;IAC1B,YAAY,EAAE,IAAK;CACX,CAAC;AAEX,8EAA8E;AAC9E,MAAM;AACN,8EAA8E;AAEjE,QAAA,oBAAoB,GAAG,KAAK,CAAC;AAC7B,QAAA,kBAAkB,GAAG,KAAK,CAAC;AAC3B,QAAA,oBAAoB,GAAG,YAAY,CAAC;AACpC,QAAA,wBAAwB,GAAG,mCAAmC,CAAC;AAE/D,QAAA,cAAc,GAAG;IAC5B,mBAAmB,EAAE,qBAAqB;IAC1C,gBAAgB,EAAE,kBAAkB;IACpC,kBAAkB,EAAE,oBAAoB;IACxC,gBAAgB,EAAE,kBAAkB;IACpC,YAAY,EAAE,cAAc;IAC5B,UAAU,EAAE,YAAY;IACxB,kBAAkB,EAAE,oBAAoB;CAChC,CAAC;AAEX,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAEjE,QAAA,YAAY,GAAG;IAC1B,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,QAAQ,EAAE,GAAG,oBAAY,WAAW;IACpC,SAAS,EAAE,GAAG,oBAAY,YAAY;IACtC,QAAQ,EAAE,GAAG,oBAAY,WAAW;IACpC,cAAc,EAAE,GAAG,oBAAY,iBAAiB;IAChD,cAAc,EAAE,GAAG,oBAAY,iBAAiB,EAAE,2CAA2C;IAC7F,aAAa,EAAE,GAAG,oBAAY,gBAAgB,EAAE,gEAAgE;IAChH,cAAc,EAAE,GAAG,oBAAY,iBAAiB,EAAE,qCAAqC;IACvF,aAAa,EAAE,GAAG,oBAAY,gBAAgB;IAC9C,iBAAiB,EAAE,GAAG,oBAAY,oBAAoB,EAAE,+CAA+C;CAC/F,CAAC;AAEX,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAEjE,QAAA,iBAAiB,GAAG,GAAG,CAAC;AACxB,QAAA,aAAa,GAAG,kBAAkB,CAAC;AACnC,QAAA,iBAAiB,GAAG,OAAO,CAAC;AAEzC,8EAA8E;AAC9E,aAAa;AACb,8EAA8E;AAEjE,QAAA,mBAAmB,GAAG,4BAA4B,CAAC;AACnD,QAAA,oBAAoB,GAAG,YAAY,CAAC;AACpC,QAAA,oBAAoB,GAAG,WAAW,CAAC;AACnC,QAAA,6BAA6B,GAAG,GAAG,CAAC;AAEjD,8EAA8E;AAC9E,qBAAqB;AACrB,8EAA8E;AAE9E,0CAA0C;AAC7B,QAAA,mBAAmB,GAAG;IACjC,UAAU;IACV,eAAe;IACf,YAAY;IACZ,aAAa;IACb,kBAAkB;IAClB,kBAAkB;IAClB,eAAe;IACf,cAAc;IACd,gBAAgB;IAChB,cAAc;IACd,YAAY;IACZ,qBAAqB;IACrB,mEAAmE;IACnE,UAAU,EAAY,kBAAkB;IACxC,cAAc,EAAQ,qBAAqB;IAC3C,YAAY,EAAU,iBAAiB;IACvC,kBAAkB,EAAI,mBAAmB;IACzC,YAAY,EAAU,mCAAmC;IACzD,mBAAmB,EAAG,sBAAsB;IAC5C,YAAY,EAAU,yBAAyB;IAC/C,6EAA6E;IAC7E,iBAAiB;IACjB,WAAW;IACX,cAAc;IACd,eAAe;IACf,qBAAqB;CACtB,CAAC;AAEF,2CAA2C;AAC9B,QAAA,eAAe,GAAG,GAAG,CAAC;AAEnC,8EAA8E;AAC9E,SAAS;AACT,8EAA8E;AAEjE,QAAA,eAAe,GAAG,wBAAwB,CAAC;AAC3C,QAAA,uBAAuB,GAAG,KAAM,CAAC;AAE9C,8EAA8E;AAC9E,OAAO;AACP,8EAA8E;AAEjE,QAAA,aAAa,GAAG;IAC3B,gBAAgB,EAAE,QAAQ;IAC1B,oBAAoB,EAAE,EAAE;CAChB,CAAC"}
|
|
@@ -2,7 +2,12 @@
|
|
|
2
2
|
* AI Gateway Routes
|
|
3
3
|
*
|
|
4
4
|
* HTTP routes for the AI Gateway that routes AI requests from WordPress
|
|
5
|
-
* to provider APIs (Anthropic, OpenAI,
|
|
5
|
+
* to provider APIs (Anthropic, OpenAI, Google) with tracking and rate limiting.
|
|
6
|
+
*
|
|
7
|
+
* Endpoints:
|
|
8
|
+
* POST /ai-gateway/v1/chat/completions — text generation (all providers)
|
|
9
|
+
* POST /ai-gateway/v1/images/generations — image generation (OpenAI)
|
|
10
|
+
* GET /ai-gateway/v1/models — list available models
|
|
6
11
|
*/
|
|
7
12
|
import * as http from 'http';
|
|
8
13
|
import type { RegistryStorage } from '../content/IndexRegistry';
|
|
@@ -25,11 +30,23 @@ export declare class AIGatewayRoutes {
|
|
|
25
30
|
* Handle /ai-gateway/v1/chat/completions endpoint
|
|
26
31
|
*/
|
|
27
32
|
handleChatCompletions(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* Handle /ai-gateway/v1/images/generations endpoint (OpenAI-compatible).
|
|
35
|
+
*/
|
|
36
|
+
handleImageGenerations(req: http.IncomingMessage, res: http.ServerResponse): Promise<void>;
|
|
28
37
|
/**
|
|
29
38
|
* Handle /ai-gateway/v1/models endpoint.
|
|
30
|
-
*
|
|
39
|
+
*
|
|
40
|
+
* Returns ONLY models for the globally configured provider — this ensures
|
|
41
|
+
* WordPress plugins surface the right model list and don't accidentally pick
|
|
42
|
+
* a model from a different provider than what the user configured.
|
|
43
|
+
*/
|
|
44
|
+
handleModels(_req: http.IncomingMessage, res: http.ServerResponse): void;
|
|
45
|
+
/**
|
|
46
|
+
* Validate X-Auth-Token and return siteId, or send 401 and return null.
|
|
31
47
|
*/
|
|
32
|
-
|
|
48
|
+
private authenticateRequest;
|
|
49
|
+
private recordAndRespond;
|
|
33
50
|
private readBody;
|
|
34
51
|
private sendError;
|
|
35
52
|
private getSiteName;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AIGatewayRoutes.d.ts","sourceRoot":"","sources":["../../../src/main/ai-gateway/AIGatewayRoutes.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"AIGatewayRoutes.d.ts","sourceRoot":"","sources":["../../../src/main/ai-gateway/AIGatewayRoutes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAShE,OAAO,EAGL,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAsFjB,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE;QACN,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;QAC5B,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;QAC7C,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;KAC7B,CAAC;IACF,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;CACxD;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAkB;IACjC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,eAAe,CAAC,CAAuC;gBAEnD,OAAO,EAAE,sBAAsB;IAM3C;;OAEG;IACG,qBAAqB,CACzB,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;IAiHhB;;OAEG;IACG,sBAAsB,CAC1B,GAAG,EAAE,IAAI,CAAC,eAAe,EACzB,GAAG,EAAE,IAAI,CAAC,cAAc,GACvB,OAAO,CAAC,IAAI,CAAC;IA8FhB;;;;;;OAMG;IACH,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,IAAI;IAoDxE;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAsB3B,OAAO,CAAC,gBAAgB;IA2DxB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,gBAAgB;CAOzB"}
|
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
* AI Gateway Routes
|
|
4
4
|
*
|
|
5
5
|
* HTTP routes for the AI Gateway that routes AI requests from WordPress
|
|
6
|
-
* to provider APIs (Anthropic, OpenAI,
|
|
6
|
+
* to provider APIs (Anthropic, OpenAI, Google) with tracking and rate limiting.
|
|
7
|
+
*
|
|
8
|
+
* Endpoints:
|
|
9
|
+
* POST /ai-gateway/v1/chat/completions — text generation (all providers)
|
|
10
|
+
* POST /ai-gateway/v1/images/generations — image generation (OpenAI)
|
|
11
|
+
* GET /ai-gateway/v1/models — list available models
|
|
7
12
|
*/
|
|
8
13
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
14
|
exports.AIGatewayRoutes = void 0;
|
|
@@ -12,26 +17,86 @@ const token_manager_1 = require("./token-manager");
|
|
|
12
17
|
const format_translator_1 = require("./format-translator");
|
|
13
18
|
const anthropic_client_1 = require("./anthropic-client");
|
|
14
19
|
const openai_client_1 = require("./openai-client");
|
|
20
|
+
const google_client_1 = require("./google-client");
|
|
21
|
+
const image_client_1 = require("./image-client");
|
|
15
22
|
const rate_limiter_1 = require("./rate-limiter");
|
|
16
23
|
/**
|
|
17
|
-
* Maps known model IDs to their provider.
|
|
18
|
-
* Extend this when adding new providers or model families.
|
|
24
|
+
* Maps known model IDs to their chat provider.
|
|
19
25
|
* Falls back to the globally configured provider for unknown models.
|
|
20
26
|
*/
|
|
21
27
|
const MODEL_PROVIDER_MAP = {
|
|
22
|
-
// Anthropic —
|
|
28
|
+
// Anthropic — current models
|
|
29
|
+
'claude-opus-4-6': 'anthropic',
|
|
30
|
+
'claude-sonnet-4-6': 'anthropic',
|
|
23
31
|
'claude-haiku-4-5-20251001': 'anthropic',
|
|
24
|
-
'claude-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
'
|
|
28
|
-
'
|
|
32
|
+
'claude-haiku-4-5': 'anthropic',
|
|
33
|
+
// Anthropic — legacy (still available)
|
|
34
|
+
'claude-sonnet-4-5-20250929': 'anthropic',
|
|
35
|
+
'claude-opus-4-5-20251101': 'anthropic',
|
|
36
|
+
'claude-sonnet-4-20250514': 'anthropic',
|
|
37
|
+
'claude-opus-4-20250514': 'anthropic',
|
|
38
|
+
// OpenAI — GPT-4.1 family
|
|
29
39
|
'gpt-4.1': 'openai',
|
|
30
40
|
'gpt-4.1-mini': 'openai',
|
|
31
|
-
'
|
|
32
|
-
|
|
41
|
+
'gpt-4.1-nano': 'openai',
|
|
42
|
+
// OpenAI — GPT-4o family
|
|
43
|
+
'gpt-4o': 'openai',
|
|
44
|
+
'gpt-4o-mini': 'openai',
|
|
45
|
+
// OpenAI — reasoning models
|
|
46
|
+
'o4-mini': 'openai',
|
|
33
47
|
'o3': 'openai',
|
|
34
48
|
'o3-mini': 'openai',
|
|
49
|
+
'o1': 'openai',
|
|
50
|
+
'o1-mini': 'openai',
|
|
51
|
+
// Google — Gemini 2.x
|
|
52
|
+
'gemini-2.5-pro': 'google',
|
|
53
|
+
'gemini-2.5-flash': 'google',
|
|
54
|
+
'gemini-2.0-flash': 'google',
|
|
55
|
+
'gemini-2.0-flash-lite': 'google',
|
|
56
|
+
// Google — Gemini 1.5
|
|
57
|
+
'gemini-1.5-pro': 'google',
|
|
58
|
+
'gemini-1.5-flash': 'google',
|
|
59
|
+
'gemini-1.5-flash-8b': 'google',
|
|
60
|
+
};
|
|
61
|
+
/** Models surfaced in /models by provider */
|
|
62
|
+
const CATALOG = {
|
|
63
|
+
anthropic: [
|
|
64
|
+
{ id: 'claude-opus-4-6', label: 'Claude Opus 4.6', tier: 'powerful' },
|
|
65
|
+
{ id: 'claude-sonnet-4-6', label: 'Claude Sonnet 4.6', tier: 'balanced' },
|
|
66
|
+
{ id: 'claude-haiku-4-5-20251001', label: 'Claude Haiku 4.5', tier: 'fast' },
|
|
67
|
+
],
|
|
68
|
+
openai: [
|
|
69
|
+
{ id: 'gpt-4.1', label: 'GPT-4.1', tier: 'powerful' },
|
|
70
|
+
{ id: 'gpt-4.1-mini', label: 'GPT-4.1 Mini', tier: 'balanced' },
|
|
71
|
+
{ id: 'gpt-4.1-nano', label: 'GPT-4.1 Nano', tier: 'fast' },
|
|
72
|
+
{ id: 'gpt-4o', label: 'GPT-4o', tier: 'powerful' },
|
|
73
|
+
{ id: 'gpt-4o-mini', label: 'GPT-4o Mini', tier: 'balanced' },
|
|
74
|
+
{ id: 'o4-mini', label: 'o4-mini', tier: 'reasoning' },
|
|
75
|
+
{ id: 'o3', label: 'o3', tier: 'reasoning' },
|
|
76
|
+
{ id: 'o3-mini', label: 'o3-mini', tier: 'reasoning' },
|
|
77
|
+
{ id: 'o1', label: 'o1', tier: 'reasoning' },
|
|
78
|
+
{ id: 'o1-mini', label: 'o1-mini', tier: 'reasoning' },
|
|
79
|
+
],
|
|
80
|
+
openai_image: [
|
|
81
|
+
{ id: 'gpt-image-1', label: 'GPT Image 1', tier: 'image' },
|
|
82
|
+
{ id: 'gpt-image-1.5', label: 'GPT Image 1.5', tier: 'image' },
|
|
83
|
+
{ id: 'gpt-image-1-mini', label: 'GPT Image 1 Mini', tier: 'image' },
|
|
84
|
+
{ id: 'dall-e-3', label: 'DALL·E 3', tier: 'image' },
|
|
85
|
+
{ id: 'dall-e-2', label: 'DALL·E 2', tier: 'image' },
|
|
86
|
+
],
|
|
87
|
+
google: [
|
|
88
|
+
{ id: 'gemini-2.5-pro', label: 'Gemini 2.5 Pro', tier: 'powerful' },
|
|
89
|
+
{ id: 'gemini-2.5-flash', label: 'Gemini 2.5 Flash', tier: 'balanced' },
|
|
90
|
+
{ id: 'gemini-2.0-flash', label: 'Gemini 2.0 Flash', tier: 'balanced' },
|
|
91
|
+
{ id: 'gemini-2.0-flash-lite', label: 'Gemini 2.0 Flash Lite', tier: 'fast' },
|
|
92
|
+
{ id: 'gemini-1.5-pro', label: 'Gemini 1.5 Pro', tier: 'powerful' },
|
|
93
|
+
{ id: 'gemini-1.5-flash', label: 'Gemini 1.5 Flash', tier: 'balanced' },
|
|
94
|
+
],
|
|
95
|
+
google_image: [
|
|
96
|
+
{ id: 'imagen-4.0-generate-001', label: 'Imagen 4', tier: 'image' },
|
|
97
|
+
{ id: 'imagen-4.0-ultra-generate-001', label: 'Imagen 4 Ultra', tier: 'image' },
|
|
98
|
+
{ id: 'imagen-4.0-fast-generate-001', label: 'Imagen 4 Fast', tier: 'image' },
|
|
99
|
+
],
|
|
35
100
|
};
|
|
36
101
|
class AIGatewayRoutes {
|
|
37
102
|
constructor(options) {
|
|
@@ -43,71 +108,34 @@ class AIGatewayRoutes {
|
|
|
43
108
|
* Handle /ai-gateway/v1/chat/completions endpoint
|
|
44
109
|
*/
|
|
45
110
|
async handleChatCompletions(req, res) {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (!authToken) {
|
|
49
|
-
this.sendError(res, 401, 'Missing X-Auth-Token header');
|
|
111
|
+
const siteId = this.authenticateRequest(req, res);
|
|
112
|
+
if (!siteId)
|
|
50
113
|
return;
|
|
51
|
-
}
|
|
52
|
-
// 2. Lookup site ID from token.
|
|
53
|
-
// Primary: per-site token registered via storeSiteToken() (nexus_ai_gateway_tokens).
|
|
54
|
-
// Fallback: validate token against the webhook auth token (http_webhook_info.authToken),
|
|
55
|
-
// which is stable and shared with the MU plugin as NEXUS_AI_AUTH_TOKEN.
|
|
56
|
-
// In that case, get the site ID from the X-WP-Site-ID header.
|
|
57
|
-
let siteId = (0, token_manager_1.getSiteIdFromToken)(this.storage, authToken);
|
|
58
|
-
if (!siteId) {
|
|
59
|
-
// Fall back to validating the shared webhook auth token + X-WP-Site-ID header.
|
|
60
|
-
// The site ID from the header is validated against the index registry so callers
|
|
61
|
-
// cannot attribute requests to arbitrary sites they don't own.
|
|
62
|
-
const webhookInfo = this.storage.get('http_webhook_info');
|
|
63
|
-
const webhookToken = webhookInfo?.authToken;
|
|
64
|
-
if (webhookToken && authToken === webhookToken) {
|
|
65
|
-
const headerSiteId = req.headers['x-wp-site-id'];
|
|
66
|
-
if (headerSiteId) {
|
|
67
|
-
const indexRegistry = this.storage.get(constants_1.STORAGE_KEYS.INDEX_REGISTRY);
|
|
68
|
-
if (indexRegistry && Object.prototype.hasOwnProperty.call(indexRegistry, headerSiteId)) {
|
|
69
|
-
siteId = headerSiteId;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (!siteId) {
|
|
75
|
-
this.sendError(res, 401, 'Invalid authentication token');
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
// 3. Parse request body
|
|
79
114
|
const body = await this.readBody(req);
|
|
80
115
|
let openAIRequest;
|
|
81
116
|
try {
|
|
82
117
|
openAIRequest = JSON.parse(body);
|
|
83
118
|
}
|
|
84
|
-
catch
|
|
119
|
+
catch {
|
|
85
120
|
this.sendError(res, 400, 'Invalid JSON in request body');
|
|
86
121
|
return;
|
|
87
122
|
}
|
|
88
|
-
// Validate required fields
|
|
89
123
|
if (!openAIRequest.model || !openAIRequest.messages) {
|
|
90
124
|
this.sendError(res, 400, 'Missing required fields: model, messages');
|
|
91
125
|
return;
|
|
92
126
|
}
|
|
93
|
-
this.logger.info(`[AIGateway]
|
|
94
|
-
// 4. Check rate limits
|
|
127
|
+
this.logger.info(`[AIGateway] Chat request from site ${siteId}: model=${openAIRequest.model}, messages=${openAIRequest.messages.length}`);
|
|
95
128
|
const rateLimitStatus = (0, rate_limiter_1.checkRateLimit)(this.storage, siteId);
|
|
96
129
|
if (!rateLimitStatus.allowed) {
|
|
97
130
|
this.logger.warn(`[AIGateway] Rate limit exceeded for site ${siteId}: ${rateLimitStatus.reason}`);
|
|
98
131
|
this.sendError(res, 429, rateLimitStatus.reason || 'Rate limit exceeded');
|
|
99
132
|
return;
|
|
100
133
|
}
|
|
101
|
-
// 5. Determine which provider to use.
|
|
102
|
-
// MODEL_PROVIDER_MAP gives an exact match for known models.
|
|
103
|
-
// Unknown models fall back to the globally configured provider.
|
|
104
134
|
const apiKeys = (this.storage.get(constants_1.STORAGE_KEYS.API_KEYS) ?? {});
|
|
105
135
|
const settings = (this.storage.get(constants_1.STORAGE_KEYS.SETTINGS) ?? {});
|
|
106
136
|
const model = openAIRequest.model;
|
|
107
|
-
const globalProvider = settings.aiProvider ?? 'anthropic';
|
|
108
|
-
const resolvedProvider = MODEL_PROVIDER_MAP[model] ?? globalProvider;
|
|
109
|
-
const useAnthropic = resolvedProvider === 'anthropic';
|
|
110
|
-
const useOpenAI = resolvedProvider === 'openai';
|
|
137
|
+
const globalProvider = (settings.aiProvider ?? 'anthropic');
|
|
138
|
+
const resolvedProvider = (MODEL_PROVIDER_MAP[model] ?? globalProvider);
|
|
111
139
|
const startTime = Date.now();
|
|
112
140
|
let openAIResponse;
|
|
113
141
|
let promptTokens;
|
|
@@ -115,13 +143,12 @@ class AIGatewayRoutes {
|
|
|
115
143
|
let responseId;
|
|
116
144
|
let actualProvider;
|
|
117
145
|
let costUsd;
|
|
118
|
-
if (
|
|
146
|
+
if (resolvedProvider === 'anthropic') {
|
|
119
147
|
const anthropicKey = apiKeys.anthropic;
|
|
120
148
|
if (!anthropicKey) {
|
|
121
149
|
this.sendError(res, 503, 'Anthropic API key not configured in Local');
|
|
122
150
|
return;
|
|
123
151
|
}
|
|
124
|
-
// 6a. Translate → Anthropic format → call → translate back
|
|
125
152
|
const anthropicRequest = (0, format_translator_1.translateToAnthropic)(openAIRequest);
|
|
126
153
|
let anthropicResponse;
|
|
127
154
|
try {
|
|
@@ -139,13 +166,12 @@ class AIGatewayRoutes {
|
|
|
139
166
|
actualProvider = 'anthropic';
|
|
140
167
|
costUsd = (0, anthropic_client_1.calculateAnthropicCost)(model, promptTokens, completionTokens);
|
|
141
168
|
}
|
|
142
|
-
else if (
|
|
169
|
+
else if (resolvedProvider === 'openai') {
|
|
143
170
|
const openaiKey = apiKeys.openai;
|
|
144
171
|
if (!openaiKey) {
|
|
145
172
|
this.sendError(res, 503, 'OpenAI API key not configured in Local');
|
|
146
173
|
return;
|
|
147
174
|
}
|
|
148
|
-
// 6b. OpenAI format is already correct — pass through directly
|
|
149
175
|
let openaiResponse;
|
|
150
176
|
try {
|
|
151
177
|
openaiResponse = await (0, openai_client_1.callOpenAIAPI)(openAIRequest, { apiKey: openaiKey, logger: this.logger });
|
|
@@ -162,19 +188,209 @@ class AIGatewayRoutes {
|
|
|
162
188
|
actualProvider = 'openai';
|
|
163
189
|
costUsd = (0, openai_client_1.calculateOpenAICost)(model, promptTokens, completionTokens);
|
|
164
190
|
}
|
|
191
|
+
else if (resolvedProvider === 'google') {
|
|
192
|
+
const googleKey = apiKeys.google;
|
|
193
|
+
if (!googleKey) {
|
|
194
|
+
this.sendError(res, 503, 'Google API key not configured in Local');
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
let googleResponse;
|
|
198
|
+
try {
|
|
199
|
+
googleResponse = await (0, google_client_1.callGoogleAPI)(openAIRequest, { apiKey: googleKey, logger: this.logger });
|
|
200
|
+
}
|
|
201
|
+
catch (err) {
|
|
202
|
+
this.logger.error('[AIGateway] Google API call failed:', err);
|
|
203
|
+
this.sendError(res, 502, `Google API error: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
openAIResponse = googleResponse;
|
|
207
|
+
promptTokens = googleResponse.usage?.prompt_tokens ?? 0;
|
|
208
|
+
completionTokens = googleResponse.usage?.completion_tokens ?? 0;
|
|
209
|
+
responseId = googleResponse.id ?? `chatcmpl-google-${Date.now()}`;
|
|
210
|
+
actualProvider = 'google';
|
|
211
|
+
costUsd = (0, google_client_1.calculateGoogleCost)(model, promptTokens, completionTokens);
|
|
212
|
+
}
|
|
165
213
|
else {
|
|
166
214
|
this.sendError(res, 503, `No API key configured for model: ${model}`);
|
|
167
215
|
return;
|
|
168
216
|
}
|
|
217
|
+
this.recordAndRespond(req, res, siteId, model, actualProvider, openAIResponse, promptTokens, completionTokens, responseId, costUsd, Date.now() - startTime);
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Handle /ai-gateway/v1/images/generations endpoint (OpenAI-compatible).
|
|
221
|
+
*/
|
|
222
|
+
async handleImageGenerations(req, res) {
|
|
223
|
+
const siteId = this.authenticateRequest(req, res);
|
|
224
|
+
if (!siteId)
|
|
225
|
+
return;
|
|
226
|
+
const body = await this.readBody(req);
|
|
227
|
+
let imageRequest;
|
|
228
|
+
try {
|
|
229
|
+
imageRequest = JSON.parse(body);
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
this.sendError(res, 400, 'Invalid JSON in request body');
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (!imageRequest.model || !imageRequest.prompt) {
|
|
236
|
+
this.sendError(res, 400, 'Missing required fields: model, prompt');
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const isGoogleImage = google_client_1.GOOGLE_IMAGE_MODELS.has(imageRequest.model);
|
|
240
|
+
const isOpenAIImage = image_client_1.IMAGE_MODELS.has(imageRequest.model);
|
|
241
|
+
if (!isGoogleImage && !isOpenAIImage) {
|
|
242
|
+
const all = [...image_client_1.IMAGE_MODELS, ...google_client_1.GOOGLE_IMAGE_MODELS].join(', ');
|
|
243
|
+
this.sendError(res, 400, `Unsupported image model: ${imageRequest.model}. Supported: ${all}`);
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
const apiKeys = (this.storage.get(constants_1.STORAGE_KEYS.API_KEYS) ?? {});
|
|
247
|
+
this.logger.info(`[AIGateway] Image request from site ${siteId}: model=${imageRequest.model}, prompt="${imageRequest.prompt.substring(0, 60)}..."`);
|
|
248
|
+
const startTime = Date.now();
|
|
249
|
+
let imageResponse;
|
|
250
|
+
let costUsd;
|
|
251
|
+
if (isGoogleImage) {
|
|
252
|
+
const googleKey = apiKeys.google;
|
|
253
|
+
if (!googleKey) {
|
|
254
|
+
this.sendError(res, 503, 'Google API key not configured in Local (required for Imagen)');
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
258
|
+
imageResponse = await (0, google_client_1.callGoogleImageAPI)(imageRequest, { apiKey: googleKey, logger: this.logger });
|
|
259
|
+
}
|
|
260
|
+
catch (err) {
|
|
261
|
+
this.logger.error('[AIGateway] Imagen API call failed:', err);
|
|
262
|
+
this.sendError(res, 502, `Imagen API error: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
costUsd = (0, google_client_1.calculateGoogleImageCost)(imageRequest.model, imageRequest.n ?? 1);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
const openaiKey = apiKeys.openai;
|
|
269
|
+
if (!openaiKey) {
|
|
270
|
+
this.sendError(res, 503, 'OpenAI API key not configured in Local (required for image generation)');
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
try {
|
|
274
|
+
imageResponse = await (0, image_client_1.callImageAPI)(imageRequest, { apiKey: openaiKey, logger: this.logger });
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
this.logger.error('[AIGateway] Image API call failed:', err);
|
|
278
|
+
this.sendError(res, 502, `Image API error: ${err instanceof Error ? err.message : 'Unknown error'}`);
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
costUsd = (0, image_client_1.calculateImageCost)(imageRequest.model, imageRequest.n ?? 1, imageRequest.size ?? '1024x1024');
|
|
282
|
+
}
|
|
169
283
|
const durationMs = Date.now() - startTime;
|
|
170
|
-
|
|
284
|
+
this.logger.info(`[AIGateway] Image success: site=${siteId}, model=${imageRequest.model}, n=${imageRequest.n ?? 1}, cost=$${costUsd.toFixed(4)}, duration=${durationMs}ms`);
|
|
285
|
+
// Record usage (no token counts for image gen)
|
|
286
|
+
const usageRecord = {
|
|
287
|
+
id: `img-${Date.now()}`,
|
|
288
|
+
siteId,
|
|
289
|
+
siteName: this.getSiteName(siteId),
|
|
290
|
+
model: imageRequest.model,
|
|
291
|
+
provider: 'openai',
|
|
292
|
+
timestamp: Date.now(),
|
|
293
|
+
promptTokens: 0,
|
|
294
|
+
completionTokens: 0,
|
|
295
|
+
totalTokens: 0,
|
|
296
|
+
costUsd,
|
|
297
|
+
durationMs,
|
|
298
|
+
};
|
|
299
|
+
this.storeUsageRecord(usageRecord);
|
|
300
|
+
if (this.onUsageRecorded)
|
|
301
|
+
this.onUsageRecorded(usageRecord);
|
|
302
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
303
|
+
res.end(JSON.stringify(imageResponse));
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Handle /ai-gateway/v1/models endpoint.
|
|
307
|
+
*
|
|
308
|
+
* Returns ONLY models for the globally configured provider — this ensures
|
|
309
|
+
* WordPress plugins surface the right model list and don't accidentally pick
|
|
310
|
+
* a model from a different provider than what the user configured.
|
|
311
|
+
*/
|
|
312
|
+
handleModels(_req, res) {
|
|
313
|
+
const apiKeys = (this.storage.get(constants_1.STORAGE_KEYS.API_KEYS) ?? {});
|
|
314
|
+
const settings = (this.storage.get(constants_1.STORAGE_KEYS.SETTINGS) ?? {});
|
|
315
|
+
const globalProvider = settings.aiProvider || 'anthropic';
|
|
316
|
+
const models = [];
|
|
317
|
+
const ts = 1700000000;
|
|
318
|
+
switch (globalProvider) {
|
|
319
|
+
case 'openai':
|
|
320
|
+
if (apiKeys.openai) {
|
|
321
|
+
for (const m of [...CATALOG.openai, ...CATALOG.openai_image]) {
|
|
322
|
+
models.push({ id: m.id, object: 'model', created: ts, owned_by: 'openai' });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
break;
|
|
326
|
+
case 'google':
|
|
327
|
+
if (apiKeys.google) {
|
|
328
|
+
for (const m of [...CATALOG.google, ...CATALOG.google_image]) {
|
|
329
|
+
models.push({ id: m.id, object: 'model', created: ts, owned_by: 'google' });
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
break;
|
|
333
|
+
case 'anthropic':
|
|
334
|
+
default:
|
|
335
|
+
if (apiKeys.anthropic) {
|
|
336
|
+
for (const m of CATALOG.anthropic) {
|
|
337
|
+
models.push({ id: m.id, object: 'model', created: ts, owned_by: 'anthropic' });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
// Fallback: no key for global provider — return that provider's catalog anyway
|
|
343
|
+
// so the plugin at least sees what models are expected (user needs to add the key)
|
|
344
|
+
if (models.length === 0) {
|
|
345
|
+
const fallback = globalProvider === 'openai' ? CATALOG.openai
|
|
346
|
+
: globalProvider === 'google' ? CATALOG.google
|
|
347
|
+
: CATALOG.anthropic;
|
|
348
|
+
for (const m of fallback) {
|
|
349
|
+
models.push({ id: m.id, object: 'model', created: ts, owned_by: globalProvider });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
353
|
+
res.end(JSON.stringify({ object: 'list', data: models }));
|
|
354
|
+
}
|
|
355
|
+
// ---------------------------------------------------------------------------
|
|
356
|
+
// Private helpers
|
|
357
|
+
// ---------------------------------------------------------------------------
|
|
358
|
+
/**
|
|
359
|
+
* Validate X-Auth-Token and return siteId, or send 401 and return null.
|
|
360
|
+
*/
|
|
361
|
+
authenticateRequest(req, res) {
|
|
362
|
+
const authToken = req.headers['x-auth-token'];
|
|
363
|
+
if (!authToken) {
|
|
364
|
+
this.sendError(res, 401, 'Missing X-Auth-Token header');
|
|
365
|
+
return null;
|
|
366
|
+
}
|
|
367
|
+
let siteId = (0, token_manager_1.getSiteIdFromToken)(this.storage, authToken);
|
|
368
|
+
if (!siteId) {
|
|
369
|
+
const webhookInfo = this.storage.get('http_webhook_info');
|
|
370
|
+
const webhookToken = webhookInfo?.authToken;
|
|
371
|
+
if (webhookToken && authToken === webhookToken) {
|
|
372
|
+
const headerSiteId = req.headers['x-wp-site-id'];
|
|
373
|
+
if (headerSiteId) {
|
|
374
|
+
const indexRegistry = this.storage.get(constants_1.STORAGE_KEYS.INDEX_REGISTRY);
|
|
375
|
+
if (indexRegistry && Object.prototype.hasOwnProperty.call(indexRegistry, headerSiteId)) {
|
|
376
|
+
siteId = headerSiteId;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
if (!siteId) {
|
|
382
|
+
this.sendError(res, 401, 'Invalid authentication token');
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
return siteId;
|
|
386
|
+
}
|
|
387
|
+
recordAndRespond(req, res, siteId, model, actualProvider, openAIResponse, promptTokens, completionTokens, responseId, costUsd, durationMs) {
|
|
171
388
|
const callerPlugin = req.headers['x-wp-caller-plugin'];
|
|
172
389
|
const callerTheme = req.headers['x-wp-caller-theme'];
|
|
173
390
|
const callerFeature = req.headers['x-wp-caller-feature'];
|
|
174
391
|
const callerSource = req.headers['x-wp-caller-source'];
|
|
175
392
|
const callerUserId = req.headers['x-wp-user-id'];
|
|
176
393
|
const callerUserRole = req.headers['x-wp-user-role'];
|
|
177
|
-
// 8. Log usage
|
|
178
394
|
const usageRecord = {
|
|
179
395
|
id: responseId,
|
|
180
396
|
siteId,
|
|
@@ -194,54 +410,24 @@ class AIGatewayRoutes {
|
|
|
194
410
|
callerUserId: callerUserId ? parseInt(callerUserId, 10) : undefined,
|
|
195
411
|
callerUserRole,
|
|
196
412
|
};
|
|
197
|
-
// Build caller description for logging
|
|
198
413
|
const callerDesc = callerPlugin
|
|
199
414
|
? `plugin:${callerPlugin}${callerFeature ? `/${callerFeature}` : ''}`
|
|
200
|
-
: callerTheme
|
|
201
|
-
? `
|
|
202
|
-
: callerSource
|
|
203
|
-
? `core:${callerFeature || callerSource}`
|
|
415
|
+
: callerTheme ? `theme:${callerTheme}`
|
|
416
|
+
: callerSource ? `core:${callerFeature || callerSource}`
|
|
204
417
|
: 'unknown';
|
|
205
418
|
this.logger.info(`[AIGateway] Success: site=${siteId}, provider=${actualProvider}, caller=${callerDesc}, model=${model}, ` +
|
|
206
|
-
`tokens=${usageRecord.totalTokens} (${
|
|
419
|
+
`tokens=${usageRecord.totalTokens} (${promptTokens}+${completionTokens}), ` +
|
|
207
420
|
`cost=$${costUsd.toFixed(4)}, duration=${durationMs}ms`);
|
|
208
|
-
// 12. Store usage record
|
|
209
421
|
this.storeUsageRecord(usageRecord);
|
|
210
|
-
|
|
211
|
-
if (this.onUsageRecorded) {
|
|
422
|
+
if (this.onUsageRecorded)
|
|
212
423
|
this.onUsageRecorded(usageRecord);
|
|
213
|
-
}
|
|
214
|
-
// 13. Return response
|
|
215
424
|
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
216
425
|
res.end(JSON.stringify(openAIResponse));
|
|
217
426
|
}
|
|
218
|
-
/**
|
|
219
|
-
* Handle /ai-gateway/v1/models endpoint.
|
|
220
|
-
* Returns models for the currently configured global provider.
|
|
221
|
-
*/
|
|
222
|
-
handleModels(req, res) {
|
|
223
|
-
const settings = (this.storage.get(constants_1.STORAGE_KEYS.SETTINGS) ?? {});
|
|
224
|
-
const provider = settings.aiProvider ?? 'anthropic';
|
|
225
|
-
const anthropicModels = [
|
|
226
|
-
{ id: 'claude-haiku-4-5-20251001', object: 'model', created: 1700000000, owned_by: 'anthropic' },
|
|
227
|
-
{ id: 'claude-sonnet-4-5-20250514', object: 'model', created: 1700000000, owned_by: 'anthropic' },
|
|
228
|
-
{ id: 'claude-opus-4-6-20251015', object: 'model', created: 1700000000, owned_by: 'anthropic' },
|
|
229
|
-
];
|
|
230
|
-
const openaiModels = [
|
|
231
|
-
{ id: 'gpt-4o-mini', object: 'model', created: 1700000000, owned_by: 'openai' },
|
|
232
|
-
{ id: 'gpt-4o', object: 'model', created: 1700000000, owned_by: 'openai' },
|
|
233
|
-
{ id: 'gpt-4.1', object: 'model', created: 1700000000, owned_by: 'openai' },
|
|
234
|
-
];
|
|
235
|
-
const models = provider === 'openai' ? openaiModels : anthropicModels;
|
|
236
|
-
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
237
|
-
res.end(JSON.stringify({ object: 'list', data: models }));
|
|
238
|
-
}
|
|
239
427
|
readBody(req) {
|
|
240
428
|
return new Promise((resolve, reject) => {
|
|
241
429
|
let body = '';
|
|
242
|
-
req.on('data', (chunk) => {
|
|
243
|
-
body += chunk.toString();
|
|
244
|
-
});
|
|
430
|
+
req.on('data', (chunk) => { body += chunk.toString(); });
|
|
245
431
|
req.on('end', () => resolve(body));
|
|
246
432
|
req.on('error', (err) => reject(err));
|
|
247
433
|
});
|
|
@@ -251,7 +437,6 @@ class AIGatewayRoutes {
|
|
|
251
437
|
res.end(JSON.stringify({ error: { message, type: 'invalid_request_error' } }));
|
|
252
438
|
}
|
|
253
439
|
getSiteName(siteId) {
|
|
254
|
-
// Look up from index registry — populated by content indexing on site start
|
|
255
440
|
const indexRegistry = this.storage.get(constants_1.STORAGE_KEYS.INDEX_REGISTRY);
|
|
256
441
|
if (indexRegistry && indexRegistry[siteId]?.siteName) {
|
|
257
442
|
return indexRegistry[siteId].siteName;
|
|
@@ -262,10 +447,8 @@ class AIGatewayRoutes {
|
|
|
262
447
|
const USAGE_KEY = 'nexus_ai_gateway_usage';
|
|
263
448
|
const records = (this.storage.get(USAGE_KEY) ?? []);
|
|
264
449
|
records.push(record);
|
|
265
|
-
|
|
266
|
-
if (records.length > 1000) {
|
|
450
|
+
if (records.length > 1000)
|
|
267
451
|
records.splice(0, records.length - 1000);
|
|
268
|
-
}
|
|
269
452
|
this.storage.set(USAGE_KEY, records);
|
|
270
453
|
}
|
|
271
454
|
}
|