@ax-llm/ax 11.0.20 → 11.0.22
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/index.cjs +297 -108
- package/index.cjs.map +1 -1
- package/index.d.cts +125 -38
- package/index.d.ts +125 -38
- package/index.js +294 -106
- package/index.js.map +1 -1
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
1
|
// ai/base.ts
|
|
2
2
|
import { SpanKind } from "@opentelemetry/api";
|
|
3
3
|
|
|
4
|
-
// dsp/modelinfo.ts
|
|
5
|
-
function getModelInfo({
|
|
6
|
-
model,
|
|
7
|
-
modelInfo,
|
|
8
|
-
models
|
|
9
|
-
}) {
|
|
10
|
-
const mappedModel = models?.find((v) => v.key === model)?.model ?? model;
|
|
11
|
-
const exactMatch = modelInfo.find((v) => v.name === model);
|
|
12
|
-
if (exactMatch) return exactMatch;
|
|
13
|
-
const normalizedName = mappedModel.replace(/^(anthropic\.|openai\.)/, "").replace(/-latest$/, "").replace(/-\d{8}$/, "").replace(/-v\d+:\d+$/, "").replace(/@\d{8}$/, "").replace(/-\d{2,}(-[a-zA-Z0-9-]+)?$/, "").replace(/-v\d+@\d{8}$/, "").replace(/-v\d+$/, "");
|
|
14
|
-
const normalizedMatch = modelInfo.find((v) => v.name === normalizedName);
|
|
15
|
-
if (normalizedMatch) return normalizedMatch;
|
|
16
|
-
return {
|
|
17
|
-
name: model,
|
|
18
|
-
currency: "usd",
|
|
19
|
-
promptTokenCostPer1M: 0,
|
|
20
|
-
completionTokenCostPer1M: 0
|
|
21
|
-
};
|
|
22
|
-
}
|
|
23
|
-
|
|
24
4
|
// trace/trace.ts
|
|
25
5
|
var axSpanAttributes = {
|
|
26
6
|
// LLM
|
|
@@ -746,6 +726,9 @@ var AxBaseAI = class {
|
|
|
746
726
|
throw new Error("No model defined");
|
|
747
727
|
}
|
|
748
728
|
this.setOptions(options);
|
|
729
|
+
if (models) {
|
|
730
|
+
validateModels(models);
|
|
731
|
+
}
|
|
749
732
|
}
|
|
750
733
|
debug = false;
|
|
751
734
|
rt;
|
|
@@ -824,33 +807,19 @@ var AxBaseAI = class {
|
|
|
824
807
|
tracer: this.tracer
|
|
825
808
|
};
|
|
826
809
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
});
|
|
833
|
-
return {
|
|
834
|
-
...mi,
|
|
835
|
-
provider: this.name
|
|
836
|
-
};
|
|
810
|
+
getModelList() {
|
|
811
|
+
return this.models?.filter((model) => !model.isInternal)?.map((model) => ({
|
|
812
|
+
key: model.key,
|
|
813
|
+
description: model.description,
|
|
814
|
+
model: model.model
|
|
815
|
+
}));
|
|
837
816
|
}
|
|
838
|
-
|
|
839
|
-
if (!this.defaults.embedModel) {
|
|
840
|
-
return;
|
|
841
|
-
}
|
|
842
|
-
const mi = getModelInfo({
|
|
843
|
-
model: this.defaults.embedModel,
|
|
844
|
-
modelInfo: this.modelInfo
|
|
845
|
-
});
|
|
817
|
+
getDefaultModels() {
|
|
846
818
|
return {
|
|
847
|
-
|
|
848
|
-
|
|
819
|
+
model: this.defaults.model,
|
|
820
|
+
embedModel: this.defaults.embedModel
|
|
849
821
|
};
|
|
850
822
|
}
|
|
851
|
-
getModelList() {
|
|
852
|
-
return this.models;
|
|
853
|
-
}
|
|
854
823
|
getName() {
|
|
855
824
|
return this.name;
|
|
856
825
|
}
|
|
@@ -1136,14 +1105,25 @@ var AxBaseAI = class {
|
|
|
1136
1105
|
return { ...headers, ...await this.headers() };
|
|
1137
1106
|
}
|
|
1138
1107
|
};
|
|
1139
|
-
|
|
1108
|
+
function setResponseAttr(res, span) {
|
|
1140
1109
|
if (res.modelUsage) {
|
|
1141
1110
|
span.setAttributes({
|
|
1142
1111
|
[axSpanAttributes.LLM_USAGE_COMPLETION_TOKENS]: res.modelUsage.completionTokens ?? 0,
|
|
1143
1112
|
[axSpanAttributes.LLM_USAGE_PROMPT_TOKENS]: res.modelUsage.promptTokens
|
|
1144
1113
|
});
|
|
1145
1114
|
}
|
|
1146
|
-
}
|
|
1115
|
+
}
|
|
1116
|
+
function validateModels(models) {
|
|
1117
|
+
const keys = /* @__PURE__ */ new Set();
|
|
1118
|
+
for (const model of models) {
|
|
1119
|
+
if (keys.has(model.key)) {
|
|
1120
|
+
throw new Error(
|
|
1121
|
+
`Duplicate model key detected: "${model.key}". Each model key must be unique.`
|
|
1122
|
+
);
|
|
1123
|
+
}
|
|
1124
|
+
keys.add(model.key);
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1147
1127
|
|
|
1148
1128
|
// ai/google-vertex/auth.ts
|
|
1149
1129
|
import { GoogleAuth } from "google-auth-library";
|
|
@@ -1799,7 +1779,7 @@ var AxAIOpenAIImpl = class {
|
|
|
1799
1779
|
response_format: this.config?.responseFormat ? { type: this.config?.responseFormat } : void 0,
|
|
1800
1780
|
tools,
|
|
1801
1781
|
tool_choice: toolsChoice,
|
|
1802
|
-
|
|
1782
|
+
max_completion_tokens: req.modelConfig?.maxTokens ?? this.config.maxTokens ?? 500,
|
|
1803
1783
|
temperature: req.modelConfig?.temperature ?? this.config.temperature,
|
|
1804
1784
|
top_p: req.modelConfig?.topP ?? this.config.topP ?? 1,
|
|
1805
1785
|
n: req.modelConfig?.n ?? this.config.n,
|
|
@@ -2596,10 +2576,10 @@ var axAIGoogleGeminiDefaultConfig = () => structuredClone({
|
|
|
2596
2576
|
...axBaseAIDefaultConfig()
|
|
2597
2577
|
});
|
|
2598
2578
|
var AxAIGoogleGeminiImpl = class {
|
|
2599
|
-
constructor(config, isVertex,
|
|
2579
|
+
constructor(config, isVertex, endpointId, apiKey, options) {
|
|
2600
2580
|
this.config = config;
|
|
2601
2581
|
this.isVertex = isVertex;
|
|
2602
|
-
this.
|
|
2582
|
+
this.endpointId = endpointId;
|
|
2603
2583
|
this.apiKey = apiKey;
|
|
2604
2584
|
this.options = options;
|
|
2605
2585
|
}
|
|
@@ -2625,9 +2605,9 @@ var AxAIGoogleGeminiImpl = class {
|
|
|
2625
2605
|
throw new Error("Chat prompt is empty");
|
|
2626
2606
|
}
|
|
2627
2607
|
let apiConfig;
|
|
2628
|
-
if (this.
|
|
2608
|
+
if (this.endpointId) {
|
|
2629
2609
|
apiConfig = {
|
|
2630
|
-
name: stream ? `/${this.
|
|
2610
|
+
name: stream ? `/${this.endpointId}:streamGenerateContent?alt=sse` : `/${this.endpointId}:generateContent`
|
|
2631
2611
|
};
|
|
2632
2612
|
} else {
|
|
2633
2613
|
apiConfig = {
|
|
@@ -2786,9 +2766,9 @@ var AxAIGoogleGeminiImpl = class {
|
|
|
2786
2766
|
let apiConfig;
|
|
2787
2767
|
let reqValue;
|
|
2788
2768
|
if (this.isVertex) {
|
|
2789
|
-
if (this.
|
|
2769
|
+
if (this.endpointId) {
|
|
2790
2770
|
apiConfig = {
|
|
2791
|
-
name: `/${this.
|
|
2771
|
+
name: `/${this.endpointId}:predict`
|
|
2792
2772
|
};
|
|
2793
2773
|
} else {
|
|
2794
2774
|
apiConfig = {
|
|
@@ -2892,7 +2872,7 @@ var AxAIGoogleGemini = class extends AxBaseAI {
|
|
|
2892
2872
|
apiKey,
|
|
2893
2873
|
projectId,
|
|
2894
2874
|
region,
|
|
2895
|
-
|
|
2875
|
+
endpointId,
|
|
2896
2876
|
config,
|
|
2897
2877
|
options,
|
|
2898
2878
|
models
|
|
@@ -2902,7 +2882,7 @@ var AxAIGoogleGemini = class extends AxBaseAI {
|
|
|
2902
2882
|
let headers;
|
|
2903
2883
|
if (isVertex) {
|
|
2904
2884
|
let path;
|
|
2905
|
-
if (
|
|
2885
|
+
if (endpointId) {
|
|
2906
2886
|
path = "endpoints";
|
|
2907
2887
|
} else {
|
|
2908
2888
|
path = "publishers/google";
|
|
@@ -2930,7 +2910,7 @@ var AxAIGoogleGemini = class extends AxBaseAI {
|
|
|
2930
2910
|
const aiImpl = new AxAIGoogleGeminiImpl(
|
|
2931
2911
|
_config,
|
|
2932
2912
|
isVertex,
|
|
2933
|
-
|
|
2913
|
+
endpointId,
|
|
2934
2914
|
apiKey,
|
|
2935
2915
|
options
|
|
2936
2916
|
);
|
|
@@ -3651,18 +3631,15 @@ var AxAI = class {
|
|
|
3651
3631
|
getId() {
|
|
3652
3632
|
return this.ai.getId();
|
|
3653
3633
|
}
|
|
3654
|
-
getModelInfo() {
|
|
3655
|
-
return this.ai.getModelInfo();
|
|
3656
|
-
}
|
|
3657
|
-
getEmbedModelInfo() {
|
|
3658
|
-
return this.ai.getEmbedModelInfo();
|
|
3659
|
-
}
|
|
3660
3634
|
getFeatures(model) {
|
|
3661
3635
|
return this.ai.getFeatures(model);
|
|
3662
3636
|
}
|
|
3663
3637
|
getModelList() {
|
|
3664
3638
|
return this.ai.getModelList();
|
|
3665
3639
|
}
|
|
3640
|
+
getDefaultModels() {
|
|
3641
|
+
return this.ai.getDefaultModels();
|
|
3642
|
+
}
|
|
3666
3643
|
getMetrics() {
|
|
3667
3644
|
return this.ai.getMetrics();
|
|
3668
3645
|
}
|
|
@@ -3899,10 +3876,11 @@ var AxAssertionError = class extends Error {
|
|
|
3899
3876
|
}
|
|
3900
3877
|
getFixingInstructions = () => {
|
|
3901
3878
|
const extraFields = [];
|
|
3879
|
+
const message = this.message.trim();
|
|
3902
3880
|
extraFields.push({
|
|
3903
3881
|
name: "error",
|
|
3904
|
-
title: "
|
|
3905
|
-
description:
|
|
3882
|
+
title: "Follow these instructions",
|
|
3883
|
+
description: message + (message.endsWith(".") ? "" : ".")
|
|
3906
3884
|
});
|
|
3907
3885
|
return extraFields;
|
|
3908
3886
|
};
|
|
@@ -5639,7 +5617,8 @@ async function processFieldProcessors(fieldProcessors, values, mem, sessionId) {
|
|
|
5639
5617
|
if (values[processor.field.name] === void 0) {
|
|
5640
5618
|
continue;
|
|
5641
5619
|
}
|
|
5642
|
-
const
|
|
5620
|
+
const processFn = processor.process;
|
|
5621
|
+
const result = await processFn(values[processor.field.name], {
|
|
5643
5622
|
sessionId,
|
|
5644
5623
|
values,
|
|
5645
5624
|
done: true
|
|
@@ -5657,7 +5636,8 @@ async function processStreamingFieldProcessors(fieldProcessors, content, xstate,
|
|
|
5657
5636
|
value = value.replace(/^[ ]*```[a-zA-Z0-9]*\n\s*/, "");
|
|
5658
5637
|
value = value.replace(/\s*```\s*$/, "");
|
|
5659
5638
|
}
|
|
5660
|
-
const
|
|
5639
|
+
const processFn = processor.process;
|
|
5640
|
+
const result = await processFn(value, {
|
|
5661
5641
|
sessionId,
|
|
5662
5642
|
values,
|
|
5663
5643
|
done
|
|
@@ -5927,7 +5907,7 @@ var AxGen = class extends AxProgramWithSignature {
|
|
|
5927
5907
|
addStreamingAssert = (fieldName, fn, message) => {
|
|
5928
5908
|
this.streamingAsserts.push({ fieldName, fn, message });
|
|
5929
5909
|
};
|
|
5930
|
-
|
|
5910
|
+
addFieldProcessorInternal = (fieldName, fn, streaming = false) => {
|
|
5931
5911
|
const field = this.signature.getOutputFields().find((f) => f.name === fieldName);
|
|
5932
5912
|
if (!field) {
|
|
5933
5913
|
throw new Error(`addFieldProcessor: field ${fieldName} not found`);
|
|
@@ -5945,6 +5925,12 @@ var AxGen = class extends AxProgramWithSignature {
|
|
|
5945
5925
|
this.fieldProcessors.push({ field, process: fn });
|
|
5946
5926
|
}
|
|
5947
5927
|
};
|
|
5928
|
+
addStreamingFieldProcessor = (fieldName, fn) => {
|
|
5929
|
+
this.addFieldProcessorInternal(fieldName, fn, true);
|
|
5930
|
+
};
|
|
5931
|
+
addFieldProcessor = (fieldName, fn) => {
|
|
5932
|
+
this.addFieldProcessorInternal(fieldName, fn, false);
|
|
5933
|
+
};
|
|
5948
5934
|
async forwardSendRequest({
|
|
5949
5935
|
ai,
|
|
5950
5936
|
mem,
|
|
@@ -5990,9 +5976,10 @@ var AxGen = class extends AxProgramWithSignature {
|
|
|
5990
5976
|
}) {
|
|
5991
5977
|
const { sessionId, traceId, model, functions } = options ?? {};
|
|
5992
5978
|
const fastFail = options?.fastFail ?? this.options?.fastFail;
|
|
5979
|
+
const modelName = model ?? ai.getDefaultModels().model;
|
|
5993
5980
|
const usageInfo = {
|
|
5994
5981
|
ai: ai.getName(),
|
|
5995
|
-
model:
|
|
5982
|
+
model: modelName
|
|
5996
5983
|
};
|
|
5997
5984
|
const res = await this.forwardSendRequest({
|
|
5998
5985
|
ai,
|
|
@@ -6076,7 +6063,9 @@ var AxGen = class extends AxProgramWithSignature {
|
|
|
6076
6063
|
content,
|
|
6077
6064
|
streamingValidation
|
|
6078
6065
|
);
|
|
6079
|
-
|
|
6066
|
+
if (this.streamingAsserts.length !== 0) {
|
|
6067
|
+
assertStreamingAssertions(this.streamingAsserts, xstate, content);
|
|
6068
|
+
}
|
|
6080
6069
|
if (this.streamingFieldProcessors.length !== 0) {
|
|
6081
6070
|
await processStreamingFieldProcessors(
|
|
6082
6071
|
this.streamingFieldProcessors,
|
|
@@ -6702,8 +6691,9 @@ var AxBalancer = class _AxBalancer {
|
|
|
6702
6691
|
if (services.length === 0) {
|
|
6703
6692
|
throw new Error("No AI services provided.");
|
|
6704
6693
|
}
|
|
6694
|
+
validateModels2(services);
|
|
6705
6695
|
this.services = [...services].sort(
|
|
6706
|
-
options?.comparator ?? _AxBalancer.
|
|
6696
|
+
options?.comparator ?? _AxBalancer.metricComparator
|
|
6707
6697
|
);
|
|
6708
6698
|
const cs = this.services[this.currentServiceIndex];
|
|
6709
6699
|
if (cs === void 0) {
|
|
@@ -6722,16 +6712,31 @@ var AxBalancer = class _AxBalancer {
|
|
|
6722
6712
|
/**
|
|
6723
6713
|
* Service comparator that sorts services by cost.
|
|
6724
6714
|
*/
|
|
6725
|
-
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6730
|
-
|
|
6715
|
+
// Requires a rethink
|
|
6716
|
+
/*
|
|
6717
|
+
public static costComparator = (a: AxAIService, b: AxAIService) => {
|
|
6718
|
+
const aInfo = a.getModelInfo()
|
|
6719
|
+
const bInfo = b.getModelInfo()
|
|
6720
|
+
const aTotalCost =
|
|
6721
|
+
(aInfo.promptTokenCostPer1M || Infinity) +
|
|
6722
|
+
(aInfo.completionTokenCostPer1M || Infinity)
|
|
6723
|
+
const bTotalCost =
|
|
6724
|
+
(bInfo.promptTokenCostPer1M || Infinity) +
|
|
6725
|
+
(bInfo.completionTokenCostPer1M || Infinity)
|
|
6726
|
+
return aTotalCost - bTotalCost
|
|
6727
|
+
}
|
|
6728
|
+
*/
|
|
6729
|
+
static metricComparator = (a, b) => {
|
|
6730
|
+
const aMetrics = a.getMetrics();
|
|
6731
|
+
const bMetrics = b.getMetrics();
|
|
6732
|
+
return aMetrics.latency.chat.mean - bMetrics.latency.chat.mean;
|
|
6731
6733
|
};
|
|
6732
6734
|
getModelList() {
|
|
6733
6735
|
return this.currentService.getModelList();
|
|
6734
6736
|
}
|
|
6737
|
+
getDefaultModels() {
|
|
6738
|
+
return this.currentService.getDefaultModels();
|
|
6739
|
+
}
|
|
6735
6740
|
getNextService() {
|
|
6736
6741
|
const cs = this.services[++this.currentServiceIndex];
|
|
6737
6742
|
if (cs === void 0) {
|
|
@@ -6754,12 +6759,6 @@ var AxBalancer = class _AxBalancer {
|
|
|
6754
6759
|
getId() {
|
|
6755
6760
|
return this.currentService.getId();
|
|
6756
6761
|
}
|
|
6757
|
-
getModelInfo() {
|
|
6758
|
-
return this.currentService.getModelInfo();
|
|
6759
|
-
}
|
|
6760
|
-
getEmbedModelInfo() {
|
|
6761
|
-
return this.currentService.getEmbedModelInfo();
|
|
6762
|
-
}
|
|
6763
6762
|
getFeatures(model) {
|
|
6764
6763
|
return this.currentService.getFeatures(model);
|
|
6765
6764
|
}
|
|
@@ -6869,6 +6868,46 @@ var AxBalancer = class _AxBalancer {
|
|
|
6869
6868
|
return this.currentService.getOptions();
|
|
6870
6869
|
}
|
|
6871
6870
|
};
|
|
6871
|
+
function validateModels2(services) {
|
|
6872
|
+
const serviceWithModel = services.find(
|
|
6873
|
+
(service) => service.getModelList() !== void 0
|
|
6874
|
+
);
|
|
6875
|
+
if (!serviceWithModel) {
|
|
6876
|
+
return;
|
|
6877
|
+
}
|
|
6878
|
+
const referenceModelList = serviceWithModel.getModelList();
|
|
6879
|
+
if (!referenceModelList) {
|
|
6880
|
+
throw new Error("No model list found in any service.");
|
|
6881
|
+
}
|
|
6882
|
+
const referenceKeys = new Set(referenceModelList.map((model) => model.key));
|
|
6883
|
+
for (let i = 0; i < services.length; i++) {
|
|
6884
|
+
const service = services[i];
|
|
6885
|
+
if (!service) {
|
|
6886
|
+
throw new Error(`Service at index ${i} is undefined`);
|
|
6887
|
+
}
|
|
6888
|
+
const modelList = service.getModelList();
|
|
6889
|
+
if (!modelList) {
|
|
6890
|
+
throw new Error(
|
|
6891
|
+
`Service at index ${i} (${service.getName()}) has no model list while another service does.`
|
|
6892
|
+
);
|
|
6893
|
+
}
|
|
6894
|
+
const serviceKeys = new Set(modelList.map((model) => model.key));
|
|
6895
|
+
for (const key of referenceKeys) {
|
|
6896
|
+
if (!serviceKeys.has(key)) {
|
|
6897
|
+
throw new Error(
|
|
6898
|
+
`Service at index ${i} (${service.getName()}) is missing model "${key}"`
|
|
6899
|
+
);
|
|
6900
|
+
}
|
|
6901
|
+
}
|
|
6902
|
+
for (const key of serviceKeys) {
|
|
6903
|
+
if (!referenceKeys.has(key)) {
|
|
6904
|
+
throw new Error(
|
|
6905
|
+
`Service at index ${i} (${service.getName()}) has extra model "${key}"`
|
|
6906
|
+
);
|
|
6907
|
+
}
|
|
6908
|
+
}
|
|
6909
|
+
}
|
|
6910
|
+
}
|
|
6872
6911
|
|
|
6873
6912
|
// dsp/optimize.ts
|
|
6874
6913
|
var AxBootstrapFewShot = class {
|
|
@@ -8100,18 +8139,6 @@ var AxMockAIService = class {
|
|
|
8100
8139
|
getId() {
|
|
8101
8140
|
return this.config.id ?? "mock-ai-service-id";
|
|
8102
8141
|
}
|
|
8103
|
-
getModelInfo() {
|
|
8104
|
-
return {
|
|
8105
|
-
name: "mock-model",
|
|
8106
|
-
provider: "mock-provider",
|
|
8107
|
-
promptTokenCostPer1M: 100,
|
|
8108
|
-
completionTokenCostPer1M: 100,
|
|
8109
|
-
...this.config.modelInfo
|
|
8110
|
-
};
|
|
8111
|
-
}
|
|
8112
|
-
getEmbedModelInfo() {
|
|
8113
|
-
return this.config.embedModelInfo;
|
|
8114
|
-
}
|
|
8115
8142
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
8116
8143
|
getFeatures(_model) {
|
|
8117
8144
|
return {
|
|
@@ -8122,6 +8149,12 @@ var AxMockAIService = class {
|
|
|
8122
8149
|
getModelList() {
|
|
8123
8150
|
return this.config.models;
|
|
8124
8151
|
}
|
|
8152
|
+
getDefaultModels() {
|
|
8153
|
+
return {
|
|
8154
|
+
model: this.config.modelInfo?.name ?? "mock-model",
|
|
8155
|
+
embedModel: this.config.embedModelInfo?.name
|
|
8156
|
+
};
|
|
8157
|
+
}
|
|
8125
8158
|
getMetrics() {
|
|
8126
8159
|
return this.metrics;
|
|
8127
8160
|
}
|
|
@@ -8199,7 +8232,7 @@ var AxMockAIService = class {
|
|
|
8199
8232
|
|
|
8200
8233
|
// dsp/router.ts
|
|
8201
8234
|
var colorLog6 = new ColorLog();
|
|
8202
|
-
var
|
|
8235
|
+
var AxSimpleClassifierClass = class {
|
|
8203
8236
|
name;
|
|
8204
8237
|
context;
|
|
8205
8238
|
constructor(name, context) {
|
|
@@ -8213,7 +8246,7 @@ var AxRoute = class {
|
|
|
8213
8246
|
return this.context;
|
|
8214
8247
|
}
|
|
8215
8248
|
};
|
|
8216
|
-
var
|
|
8249
|
+
var AxSimpleClassifier = class {
|
|
8217
8250
|
ai;
|
|
8218
8251
|
db;
|
|
8219
8252
|
debug;
|
|
@@ -8227,12 +8260,12 @@ var AxRouter = class {
|
|
|
8227
8260
|
setState(state) {
|
|
8228
8261
|
this.db.setDB(state);
|
|
8229
8262
|
}
|
|
8230
|
-
|
|
8231
|
-
for (const
|
|
8232
|
-
const ret = await this.ai.embed({ texts:
|
|
8263
|
+
setClasses = async (classes) => {
|
|
8264
|
+
for (const c of classes) {
|
|
8265
|
+
const ret = await this.ai.embed({ texts: c.getContext() });
|
|
8233
8266
|
await this.db.upsert({
|
|
8234
|
-
id:
|
|
8235
|
-
table: "
|
|
8267
|
+
id: c.getName(),
|
|
8268
|
+
table: "classes",
|
|
8236
8269
|
values: ret.embeddings[0]
|
|
8237
8270
|
});
|
|
8238
8271
|
}
|
|
@@ -8240,7 +8273,7 @@ var AxRouter = class {
|
|
|
8240
8273
|
async forward(text, options) {
|
|
8241
8274
|
const { embeddings } = await this.ai.embed({ texts: [text] });
|
|
8242
8275
|
const matches = await this.db.query({
|
|
8243
|
-
table: "
|
|
8276
|
+
table: "classes",
|
|
8244
8277
|
values: embeddings[0]
|
|
8245
8278
|
});
|
|
8246
8279
|
let m = matches.matches;
|
|
@@ -8255,11 +8288,11 @@ var AxRouter = class {
|
|
|
8255
8288
|
)
|
|
8256
8289
|
);
|
|
8257
8290
|
}
|
|
8258
|
-
const
|
|
8259
|
-
if (!
|
|
8291
|
+
const matchedClass = m.at(0);
|
|
8292
|
+
if (!matchedClass) {
|
|
8260
8293
|
return "";
|
|
8261
8294
|
}
|
|
8262
|
-
return
|
|
8295
|
+
return matchedClass.id;
|
|
8263
8296
|
}
|
|
8264
8297
|
setOptions(options) {
|
|
8265
8298
|
if (typeof options.debug === "boolean") {
|
|
@@ -8466,6 +8499,160 @@ var AxEmbeddingAdapter = class {
|
|
|
8466
8499
|
}
|
|
8467
8500
|
};
|
|
8468
8501
|
|
|
8502
|
+
// ai/multiservice.ts
|
|
8503
|
+
var AxMultiServiceRouter = class {
|
|
8504
|
+
services = /* @__PURE__ */ new Map();
|
|
8505
|
+
/**
|
|
8506
|
+
* Constructs a new multi-service router.
|
|
8507
|
+
* It validates that each service provides a unique set of model keys,
|
|
8508
|
+
* then builds a lookup (map) for routing the chat/embed requests.
|
|
8509
|
+
*/
|
|
8510
|
+
constructor(services) {
|
|
8511
|
+
if (services.length === 0) {
|
|
8512
|
+
throw new Error("No AI services provided.");
|
|
8513
|
+
}
|
|
8514
|
+
for (const [index, item] of services.entries()) {
|
|
8515
|
+
const isKeyBased = "key" in item;
|
|
8516
|
+
if (isKeyBased) {
|
|
8517
|
+
if (this.services.has(item.key)) {
|
|
8518
|
+
throw new Error(`Duplicate model key: ${item.key}`);
|
|
8519
|
+
}
|
|
8520
|
+
const { service, description, isInternal } = item;
|
|
8521
|
+
this.services.set(item.key, {
|
|
8522
|
+
service,
|
|
8523
|
+
description,
|
|
8524
|
+
isInternal,
|
|
8525
|
+
model: item.service.getDefaultModels().model,
|
|
8526
|
+
useDefaultModel: true
|
|
8527
|
+
});
|
|
8528
|
+
} else {
|
|
8529
|
+
const modelList = item.getModelList();
|
|
8530
|
+
if (!modelList) {
|
|
8531
|
+
throw new Error(
|
|
8532
|
+
`Service ${index} \`${item.getName()}\` has no model list.`
|
|
8533
|
+
);
|
|
8534
|
+
}
|
|
8535
|
+
for (const { key, description, model } of modelList ?? []) {
|
|
8536
|
+
if (this.services.has(key)) {
|
|
8537
|
+
const otherService = this.services.get(key)?.service;
|
|
8538
|
+
throw new Error(
|
|
8539
|
+
`Service ${index} \`${item.getName()}\` has duplicate model key: ${key} as service ${otherService?.getName()}`
|
|
8540
|
+
);
|
|
8541
|
+
}
|
|
8542
|
+
this.services.set(key, {
|
|
8543
|
+
description,
|
|
8544
|
+
service: item,
|
|
8545
|
+
model
|
|
8546
|
+
});
|
|
8547
|
+
}
|
|
8548
|
+
}
|
|
8549
|
+
}
|
|
8550
|
+
}
|
|
8551
|
+
/**
|
|
8552
|
+
* Delegates the chat call to the service matching the provided model key.
|
|
8553
|
+
*/
|
|
8554
|
+
async chat(req, options) {
|
|
8555
|
+
const modelKey = req.model;
|
|
8556
|
+
if (!modelKey) {
|
|
8557
|
+
throw new Error("Model key must be specified for multi-service");
|
|
8558
|
+
}
|
|
8559
|
+
const item = this.services.get(modelKey);
|
|
8560
|
+
if (!item) {
|
|
8561
|
+
throw new Error(`No service found for model key: ${modelKey}`);
|
|
8562
|
+
}
|
|
8563
|
+
const service = item.service;
|
|
8564
|
+
const model = item.useDefaultModel ? req.model : modelKey;
|
|
8565
|
+
return await service.chat({ model, ...req }, options);
|
|
8566
|
+
}
|
|
8567
|
+
/**
|
|
8568
|
+
* Delegates the embed call to the service matching the provided embed model key.
|
|
8569
|
+
*/
|
|
8570
|
+
async embed(req, options) {
|
|
8571
|
+
const modelKey = req.embedModel;
|
|
8572
|
+
if (!modelKey) {
|
|
8573
|
+
throw new Error("Embed model key must be specified for multi-service");
|
|
8574
|
+
}
|
|
8575
|
+
const item = this.services.get(modelKey);
|
|
8576
|
+
if (!item) {
|
|
8577
|
+
throw new Error(`No service found for embed model key: ${modelKey}`);
|
|
8578
|
+
}
|
|
8579
|
+
const service = item.service;
|
|
8580
|
+
const embedModel = item.useDefaultModel ? req.embedModel : modelKey;
|
|
8581
|
+
return await service.embed({ embedModel, ...req }, options);
|
|
8582
|
+
}
|
|
8583
|
+
/**
|
|
8584
|
+
* Returns a composite ID built from the IDs of the underlying services.
|
|
8585
|
+
*/
|
|
8586
|
+
getId() {
|
|
8587
|
+
return "MultiServiceRouter:" + Array.from(this.services.values()).map((s) => s.service.getId()).join(",");
|
|
8588
|
+
}
|
|
8589
|
+
/**
|
|
8590
|
+
* Returns the name of this router.
|
|
8591
|
+
*/
|
|
8592
|
+
getName() {
|
|
8593
|
+
return "MultiServiceRouter";
|
|
8594
|
+
}
|
|
8595
|
+
/**
|
|
8596
|
+
* Aggregates all available models across the underlying services.
|
|
8597
|
+
*/
|
|
8598
|
+
getModelList() {
|
|
8599
|
+
return Array.from(this.services).filter(([, value]) => !value.isInternal).map(([key, { description, model }]) => ({
|
|
8600
|
+
key,
|
|
8601
|
+
description,
|
|
8602
|
+
model
|
|
8603
|
+
}));
|
|
8604
|
+
}
|
|
8605
|
+
getDefaultModels() {
|
|
8606
|
+
throw new Error(
|
|
8607
|
+
"getDefaultModels is not supported for multi-service router."
|
|
8608
|
+
);
|
|
8609
|
+
}
|
|
8610
|
+
/**
|
|
8611
|
+
* If a model key is provided, delegate to the corresponding service's features.
|
|
8612
|
+
* Otherwise, returns a default feature set.
|
|
8613
|
+
*/
|
|
8614
|
+
getFeatures(model) {
|
|
8615
|
+
if (model) {
|
|
8616
|
+
const service = this.services.get(model);
|
|
8617
|
+
if (service) {
|
|
8618
|
+
return service.service.getFeatures(model);
|
|
8619
|
+
}
|
|
8620
|
+
}
|
|
8621
|
+
return { functions: false, streaming: false };
|
|
8622
|
+
}
|
|
8623
|
+
/**
|
|
8624
|
+
* Returns aggregated metrics from the underlying service.
|
|
8625
|
+
* Uses the metrics from the last service that was used,
|
|
8626
|
+
* or falls back to the first service if none has been used.
|
|
8627
|
+
*/
|
|
8628
|
+
getMetrics() {
|
|
8629
|
+
const service = this.services.values().next().value;
|
|
8630
|
+
if (!service) {
|
|
8631
|
+
throw new Error("No service available to get metrics.");
|
|
8632
|
+
}
|
|
8633
|
+
return service.service.getMetrics();
|
|
8634
|
+
}
|
|
8635
|
+
/**
|
|
8636
|
+
* Sets options on all underlying services.
|
|
8637
|
+
*/
|
|
8638
|
+
setOptions(options) {
|
|
8639
|
+
for (const service of this.services.values()) {
|
|
8640
|
+
service.service.setOptions(options);
|
|
8641
|
+
}
|
|
8642
|
+
}
|
|
8643
|
+
/**
|
|
8644
|
+
* Returns the options from the last used service,
|
|
8645
|
+
* or falls back to the first service if none has been used.
|
|
8646
|
+
*/
|
|
8647
|
+
getOptions() {
|
|
8648
|
+
const service = this.services.values().next().value;
|
|
8649
|
+
if (!service) {
|
|
8650
|
+
throw new Error("No service available to get options.");
|
|
8651
|
+
}
|
|
8652
|
+
return service.service.getOptions();
|
|
8653
|
+
}
|
|
8654
|
+
};
|
|
8655
|
+
|
|
8469
8656
|
// prompts/rag.ts
|
|
8470
8657
|
var AxRAG = class extends AxChainOfThought {
|
|
8471
8658
|
genQuery;
|
|
@@ -8565,14 +8752,15 @@ export {
|
|
|
8565
8752
|
AxLLMRequestTypeValues,
|
|
8566
8753
|
AxMemory,
|
|
8567
8754
|
AxMockAIService,
|
|
8755
|
+
AxMultiServiceRouter,
|
|
8568
8756
|
AxProgram,
|
|
8569
8757
|
AxProgramWithSignature,
|
|
8570
8758
|
AxPromptTemplate,
|
|
8571
8759
|
AxRAG,
|
|
8572
8760
|
AxRateLimiterTokenUsage,
|
|
8573
|
-
AxRoute,
|
|
8574
|
-
AxRouter,
|
|
8575
8761
|
AxSignature,
|
|
8762
|
+
AxSimpleClassifier,
|
|
8763
|
+
AxSimpleClassifierClass,
|
|
8576
8764
|
AxSpanKindValues,
|
|
8577
8765
|
AxTestPrompt
|
|
8578
8766
|
};
|