@kortexya/reasoninglayer 0.2.1 → 0.2.3
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/README.md +9 -3
- package/dist/index.cjs +559 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +464 -2
- package/dist/index.d.ts +464 -2
- package/dist/index.js +559 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/config.ts
|
|
2
|
-
var SDK_VERSION = "0.2.
|
|
2
|
+
var SDK_VERSION = "0.2.3";
|
|
3
3
|
function resolveConfig(config) {
|
|
4
4
|
if (!config.baseUrl) {
|
|
5
5
|
throw new Error("ClientConfig.baseUrl is required");
|
|
@@ -12546,6 +12546,560 @@ var RagClient = class {
|
|
|
12546
12546
|
}
|
|
12547
12547
|
};
|
|
12548
12548
|
|
|
12549
|
+
// src/builders/lp.ts
|
|
12550
|
+
function numericTerm(n) {
|
|
12551
|
+
return {
|
|
12552
|
+
sort_name: Number.isInteger(n) ? "integer_type" : "real_type",
|
|
12553
|
+
features: { value: n }
|
|
12554
|
+
};
|
|
12555
|
+
}
|
|
12556
|
+
var LP = {
|
|
12557
|
+
/**
|
|
12558
|
+
* Create a maximization objective.
|
|
12559
|
+
*
|
|
12560
|
+
* @param coefficients - Map of variable names to their objective coefficients.
|
|
12561
|
+
* @returns An objective function to maximize.
|
|
12562
|
+
*
|
|
12563
|
+
* @remarks Serialization format: SDK-internal (compiled to constraint sorts).
|
|
12564
|
+
*
|
|
12565
|
+
* @example
|
|
12566
|
+
* ```typescript
|
|
12567
|
+
* LP.maximize({ chairs: 3, tables: 5 })
|
|
12568
|
+
* // { direction: 'maximize', coefficients: { chairs: 3, tables: 5 } }
|
|
12569
|
+
* ```
|
|
12570
|
+
*/
|
|
12571
|
+
maximize(coefficients) {
|
|
12572
|
+
return { direction: "maximize", coefficients };
|
|
12573
|
+
},
|
|
12574
|
+
/**
|
|
12575
|
+
* Create a minimization objective.
|
|
12576
|
+
*
|
|
12577
|
+
* @param coefficients - Map of variable names to their objective coefficients.
|
|
12578
|
+
* @returns An objective function to minimize.
|
|
12579
|
+
*
|
|
12580
|
+
* @remarks Serialization format: SDK-internal (compiled to constraint sorts).
|
|
12581
|
+
*
|
|
12582
|
+
* @example
|
|
12583
|
+
* ```typescript
|
|
12584
|
+
* LP.minimize({ cost_a: 2, cost_b: 5 })
|
|
12585
|
+
* // { direction: 'minimize', coefficients: { cost_a: 2, cost_b: 5 } }
|
|
12586
|
+
* ```
|
|
12587
|
+
*/
|
|
12588
|
+
minimize(coefficients) {
|
|
12589
|
+
return { direction: "minimize", coefficients };
|
|
12590
|
+
},
|
|
12591
|
+
/**
|
|
12592
|
+
* Create a linear constraint.
|
|
12593
|
+
*
|
|
12594
|
+
* @param coefficients - Map of variable names to their constraint coefficients.
|
|
12595
|
+
* @param op - Comparison operator: '<=', '>=', or '='.
|
|
12596
|
+
* @param rhs - Right-hand side constant.
|
|
12597
|
+
* @param label - Optional human-readable label.
|
|
12598
|
+
* @returns A linear constraint.
|
|
12599
|
+
*
|
|
12600
|
+
* @remarks Serialization format: SDK-internal (compiled to constraint sorts).
|
|
12601
|
+
*
|
|
12602
|
+
* @example
|
|
12603
|
+
* ```typescript
|
|
12604
|
+
* LP.constraint({ chairs: 1, tables: 3 }, '<=', 12, 'wood')
|
|
12605
|
+
* // { coefficients: { chairs: 1, tables: 3 }, op: '<=', rhs: 12, label: 'wood' }
|
|
12606
|
+
* ```
|
|
12607
|
+
*/
|
|
12608
|
+
constraint(coefficients, op, rhs, label) {
|
|
12609
|
+
return label !== void 0 ? { coefficients, op, rhs, label } : { coefficients, op, rhs };
|
|
12610
|
+
},
|
|
12611
|
+
/**
|
|
12612
|
+
* Create non-negativity bounds (>= 0) for the given variables.
|
|
12613
|
+
*
|
|
12614
|
+
* @param variables - Variable names to constrain to be non-negative.
|
|
12615
|
+
* @returns A bounds map with `{ min: 0 }` for each variable.
|
|
12616
|
+
*
|
|
12617
|
+
* @remarks Serialization format: SDK-internal (compiled to constraint sorts).
|
|
12618
|
+
*
|
|
12619
|
+
* @example
|
|
12620
|
+
* ```typescript
|
|
12621
|
+
* LP.nonNegative('chairs', 'tables')
|
|
12622
|
+
* // { chairs: { min: 0 }, tables: { min: 0 } }
|
|
12623
|
+
* ```
|
|
12624
|
+
*/
|
|
12625
|
+
nonNegative(...variables) {
|
|
12626
|
+
const bounds = {};
|
|
12627
|
+
for (const v of variables) {
|
|
12628
|
+
bounds[v] = { min: 0 };
|
|
12629
|
+
}
|
|
12630
|
+
return bounds;
|
|
12631
|
+
},
|
|
12632
|
+
/**
|
|
12633
|
+
* Create bounds for a variable.
|
|
12634
|
+
*
|
|
12635
|
+
* @param min - Lower bound (omit for unbounded below).
|
|
12636
|
+
* @param max - Upper bound (omit for unbounded above).
|
|
12637
|
+
* @returns Variable bounds specification.
|
|
12638
|
+
*
|
|
12639
|
+
* @remarks Serialization format: SDK-internal (compiled to constraint sorts).
|
|
12640
|
+
*
|
|
12641
|
+
* @example
|
|
12642
|
+
* ```typescript
|
|
12643
|
+
* LP.bounds(0, 100)
|
|
12644
|
+
* // { min: 0, max: 100 }
|
|
12645
|
+
* ```
|
|
12646
|
+
*/
|
|
12647
|
+
bounds(min, max) {
|
|
12648
|
+
const b = {};
|
|
12649
|
+
if (min !== void 0) b.min = min;
|
|
12650
|
+
if (max !== void 0) b.max = max;
|
|
12651
|
+
return b;
|
|
12652
|
+
}
|
|
12653
|
+
};
|
|
12654
|
+
function compileLP(problem, solutionSortName) {
|
|
12655
|
+
const counter = { value: 0 };
|
|
12656
|
+
const nextVar = () => `?_lp_${counter.value++}`;
|
|
12657
|
+
const variableNames = discoverVariables(problem);
|
|
12658
|
+
if (variableNames.length === 0) {
|
|
12659
|
+
throw new Error("LP problem has no variables. At least one variable must appear in the objective or constraints.");
|
|
12660
|
+
}
|
|
12661
|
+
const varRefs = {};
|
|
12662
|
+
for (const name of variableNames) {
|
|
12663
|
+
varRefs[name] = { name: `?${name}` };
|
|
12664
|
+
}
|
|
12665
|
+
const allAntecedents = [];
|
|
12666
|
+
if (problem.bounds) {
|
|
12667
|
+
for (const [varName, bounds] of Object.entries(problem.bounds)) {
|
|
12668
|
+
if (!(varName in varRefs)) continue;
|
|
12669
|
+
const ref = varRefs[varName];
|
|
12670
|
+
if (bounds.min !== void 0 && bounds.max !== void 0) {
|
|
12671
|
+
allAntecedents.push({
|
|
12672
|
+
sort_name: "real_between_constraint",
|
|
12673
|
+
features: {
|
|
12674
|
+
var: ref,
|
|
12675
|
+
lower: numericTerm(bounds.min),
|
|
12676
|
+
upper: numericTerm(bounds.max)
|
|
12677
|
+
}
|
|
12678
|
+
});
|
|
12679
|
+
} else {
|
|
12680
|
+
if (bounds.min !== void 0) {
|
|
12681
|
+
allAntecedents.push({
|
|
12682
|
+
sort_name: "real_ge_constraint",
|
|
12683
|
+
features: {
|
|
12684
|
+
left: ref,
|
|
12685
|
+
right: numericTerm(bounds.min)
|
|
12686
|
+
}
|
|
12687
|
+
});
|
|
12688
|
+
}
|
|
12689
|
+
if (bounds.max !== void 0) {
|
|
12690
|
+
allAntecedents.push({
|
|
12691
|
+
sort_name: "real_le_constraint",
|
|
12692
|
+
features: {
|
|
12693
|
+
left: ref,
|
|
12694
|
+
right: numericTerm(bounds.max)
|
|
12695
|
+
}
|
|
12696
|
+
});
|
|
12697
|
+
}
|
|
12698
|
+
}
|
|
12699
|
+
}
|
|
12700
|
+
}
|
|
12701
|
+
for (const constraint of problem.constraints) {
|
|
12702
|
+
const compiled = compileLinearExpression(constraint.coefficients, varRefs, nextVar);
|
|
12703
|
+
allAntecedents.push(...compiled.antecedents);
|
|
12704
|
+
const sortName = constraintOpToSort(constraint.op);
|
|
12705
|
+
allAntecedents.push({
|
|
12706
|
+
sort_name: sortName,
|
|
12707
|
+
features: {
|
|
12708
|
+
left: compiled.resultRef,
|
|
12709
|
+
right: numericTerm(constraint.rhs)
|
|
12710
|
+
}
|
|
12711
|
+
});
|
|
12712
|
+
}
|
|
12713
|
+
const objectiveCompiled = compileLinearExpression(
|
|
12714
|
+
problem.objective.coefficients,
|
|
12715
|
+
varRefs,
|
|
12716
|
+
nextVar
|
|
12717
|
+
);
|
|
12718
|
+
allAntecedents.push(...objectiveCompiled.antecedents);
|
|
12719
|
+
let objectiveRef = objectiveCompiled.resultRef;
|
|
12720
|
+
if (typeof objectiveRef === "number") {
|
|
12721
|
+
const objVar = { name: "?_lp_objective" };
|
|
12722
|
+
allAntecedents.push({
|
|
12723
|
+
sort_name: "real_eq_constraint",
|
|
12724
|
+
features: {
|
|
12725
|
+
left: objVar,
|
|
12726
|
+
right: numericTerm(objectiveRef)
|
|
12727
|
+
}
|
|
12728
|
+
});
|
|
12729
|
+
objectiveRef = objVar;
|
|
12730
|
+
}
|
|
12731
|
+
const objectiveSortName = problem.objective.direction === "maximize" ? "maximize_objective" : "minimize_objective";
|
|
12732
|
+
allAntecedents.push({
|
|
12733
|
+
sort_name: objectiveSortName,
|
|
12734
|
+
features: {
|
|
12735
|
+
expression: objectiveRef,
|
|
12736
|
+
name: "objective"
|
|
12737
|
+
}
|
|
12738
|
+
});
|
|
12739
|
+
const variableRefList = variableNames.map(
|
|
12740
|
+
(name) => varRefs[name]
|
|
12741
|
+
);
|
|
12742
|
+
allAntecedents.push({
|
|
12743
|
+
sort_name: "real_labeling_constraint",
|
|
12744
|
+
features: {
|
|
12745
|
+
variables: variableRefList
|
|
12746
|
+
}
|
|
12747
|
+
});
|
|
12748
|
+
const solutionFeatures = {};
|
|
12749
|
+
for (const name of variableNames) {
|
|
12750
|
+
solutionFeatures[name] = varRefs[name];
|
|
12751
|
+
}
|
|
12752
|
+
solutionFeatures["_objective"] = objectiveRef;
|
|
12753
|
+
const solutionTerm = {
|
|
12754
|
+
sort_name: solutionSortName,
|
|
12755
|
+
features: solutionFeatures
|
|
12756
|
+
};
|
|
12757
|
+
return { solutionTerm, antecedents: allAntecedents };
|
|
12758
|
+
}
|
|
12759
|
+
function discoverVariables(problem) {
|
|
12760
|
+
const vars = /* @__PURE__ */ new Set();
|
|
12761
|
+
for (const name of Object.keys(problem.objective.coefficients)) {
|
|
12762
|
+
vars.add(name);
|
|
12763
|
+
}
|
|
12764
|
+
for (const constraint of problem.constraints) {
|
|
12765
|
+
for (const name of Object.keys(constraint.coefficients)) {
|
|
12766
|
+
vars.add(name);
|
|
12767
|
+
}
|
|
12768
|
+
}
|
|
12769
|
+
if (problem.bounds) {
|
|
12770
|
+
for (const name of Object.keys(problem.bounds)) {
|
|
12771
|
+
vars.add(name);
|
|
12772
|
+
}
|
|
12773
|
+
}
|
|
12774
|
+
return Array.from(vars).sort();
|
|
12775
|
+
}
|
|
12776
|
+
function compileLinearExpression(expression, varRefs, nextVar) {
|
|
12777
|
+
const antecedents = [];
|
|
12778
|
+
const termResults = [];
|
|
12779
|
+
for (const [varName, coefficient] of Object.entries(expression)) {
|
|
12780
|
+
if (coefficient === 0) continue;
|
|
12781
|
+
const varRef = varRefs[varName];
|
|
12782
|
+
if (!varRef) continue;
|
|
12783
|
+
if (coefficient === 1) {
|
|
12784
|
+
termResults.push(varRef);
|
|
12785
|
+
} else {
|
|
12786
|
+
const resultVar = { name: nextVar() };
|
|
12787
|
+
antecedents.push({
|
|
12788
|
+
sort_name: "real_times_constraint",
|
|
12789
|
+
features: {
|
|
12790
|
+
coefficient: numericTerm(coefficient),
|
|
12791
|
+
variable: varRef,
|
|
12792
|
+
result: resultVar
|
|
12793
|
+
}
|
|
12794
|
+
});
|
|
12795
|
+
termResults.push(resultVar);
|
|
12796
|
+
}
|
|
12797
|
+
}
|
|
12798
|
+
if (termResults.length === 0) {
|
|
12799
|
+
return { antecedents, resultRef: numericTerm(0) };
|
|
12800
|
+
}
|
|
12801
|
+
if (termResults.length === 1) {
|
|
12802
|
+
return { antecedents, resultRef: termResults[0] };
|
|
12803
|
+
}
|
|
12804
|
+
let current = termResults[0];
|
|
12805
|
+
for (let i = 1; i < termResults.length; i++) {
|
|
12806
|
+
const sumVar = { name: nextVar() };
|
|
12807
|
+
antecedents.push({
|
|
12808
|
+
sort_name: "real_plus_constraint",
|
|
12809
|
+
features: {
|
|
12810
|
+
left: current,
|
|
12811
|
+
right: termResults[i],
|
|
12812
|
+
result: sumVar
|
|
12813
|
+
}
|
|
12814
|
+
});
|
|
12815
|
+
current = sumVar;
|
|
12816
|
+
}
|
|
12817
|
+
return { antecedents, resultRef: current };
|
|
12818
|
+
}
|
|
12819
|
+
function constraintOpToSort(op) {
|
|
12820
|
+
switch (op) {
|
|
12821
|
+
case "<=":
|
|
12822
|
+
return "real_le_constraint";
|
|
12823
|
+
case ">=":
|
|
12824
|
+
return "real_ge_constraint";
|
|
12825
|
+
case "=":
|
|
12826
|
+
return "real_eq_constraint";
|
|
12827
|
+
}
|
|
12828
|
+
}
|
|
12829
|
+
|
|
12830
|
+
// src/resources/optimize.ts
|
|
12831
|
+
var OptimizeClient = class {
|
|
12832
|
+
/** @internal */
|
|
12833
|
+
inferenceApi;
|
|
12834
|
+
/** @internal */
|
|
12835
|
+
sortsApi;
|
|
12836
|
+
/** @internal */
|
|
12837
|
+
queryApi;
|
|
12838
|
+
/** @internal */
|
|
12839
|
+
termsApi;
|
|
12840
|
+
/** @internal */
|
|
12841
|
+
tenantId;
|
|
12842
|
+
/** @internal */
|
|
12843
|
+
constructor(inferenceApi, sortsApi, queryApi, termsApi, tenantId) {
|
|
12844
|
+
this.inferenceApi = inferenceApi;
|
|
12845
|
+
this.sortsApi = sortsApi;
|
|
12846
|
+
this.queryApi = queryApi;
|
|
12847
|
+
this.termsApi = termsApi;
|
|
12848
|
+
this.tenantId = tenantId;
|
|
12849
|
+
}
|
|
12850
|
+
/**
|
|
12851
|
+
* Solve a linear program.
|
|
12852
|
+
*
|
|
12853
|
+
* @param problem - The LP problem definition with objective, constraints, and bounds.
|
|
12854
|
+
* @param options - Optional solver configuration (timeout, cleanup, etc.).
|
|
12855
|
+
* @returns The optimization result with variable values and objective value.
|
|
12856
|
+
*
|
|
12857
|
+
* @throws {Error} If the problem has no variables.
|
|
12858
|
+
*
|
|
12859
|
+
* @remarks
|
|
12860
|
+
* Internally creates a temporary sort and inference rule, runs backward chaining
|
|
12861
|
+
* to trigger the CLP(Q) simplex solver, then cleans up temporary artifacts.
|
|
12862
|
+
*
|
|
12863
|
+
* The solver uses exact rational arithmetic (Rational64). Solutions are converted
|
|
12864
|
+
* to JavaScript numbers (f64 approximation) for the response.
|
|
12865
|
+
*
|
|
12866
|
+
* @example
|
|
12867
|
+
* ```typescript
|
|
12868
|
+
* import { LP } from '@kortexya/reasoninglayer';
|
|
12869
|
+
*
|
|
12870
|
+
* const result = await client.optimize.solve({
|
|
12871
|
+
* objective: LP.maximize({ x: 1, y: 2 }),
|
|
12872
|
+
* constraints: [
|
|
12873
|
+
* LP.constraint({ x: 1, y: 1 }, '<=', 10),
|
|
12874
|
+
* ],
|
|
12875
|
+
* bounds: LP.nonNegative('x', 'y'),
|
|
12876
|
+
* });
|
|
12877
|
+
*
|
|
12878
|
+
* if (result.status === 'optimal') {
|
|
12879
|
+
* console.log(result.variables); // { x: 0, y: 10 }
|
|
12880
|
+
* console.log(result.objectiveValue); // 20
|
|
12881
|
+
* }
|
|
12882
|
+
* ```
|
|
12883
|
+
*/
|
|
12884
|
+
async solve(problem, options) {
|
|
12885
|
+
const cleanup = options?.cleanup !== false;
|
|
12886
|
+
const timeoutMs = options?.timeoutMs ?? 3e4;
|
|
12887
|
+
const maxDepth = options?.maxDepth ?? 50;
|
|
12888
|
+
const suffix = generateShortId();
|
|
12889
|
+
const solutionSortName = `_lp_solution_${suffix}`;
|
|
12890
|
+
const compiled = compileLP(problem, solutionSortName);
|
|
12891
|
+
let sortId;
|
|
12892
|
+
let ruleTermId;
|
|
12893
|
+
try {
|
|
12894
|
+
const sortResponse = await this.sortsApi.bulkCreateSorts({
|
|
12895
|
+
sorts: [{ name: solutionSortName, parents: ["thing"] }]
|
|
12896
|
+
});
|
|
12897
|
+
sortId = sortResponse.data.sort_ids[solutionSortName];
|
|
12898
|
+
const ruleResponse = await this.inferenceApi.addRule({
|
|
12899
|
+
term: compiled.solutionTerm,
|
|
12900
|
+
antecedents: compiled.antecedents,
|
|
12901
|
+
certainty: 1
|
|
12902
|
+
});
|
|
12903
|
+
ruleTermId = ruleResponse.data.term.term_id;
|
|
12904
|
+
const bcResponse = await this.inferenceApi.backwardChain({
|
|
12905
|
+
goal: { sort_name: solutionSortName },
|
|
12906
|
+
max_solutions: 1,
|
|
12907
|
+
max_depth: maxDepth,
|
|
12908
|
+
timeout_ms: timeoutMs
|
|
12909
|
+
});
|
|
12910
|
+
const queryTimeMs = bcResponse.data.query_time_ms;
|
|
12911
|
+
if (bcResponse.data.solutions.length === 0) {
|
|
12912
|
+
return { status: "infeasible", solveTimeMs: queryTimeMs };
|
|
12913
|
+
}
|
|
12914
|
+
const solution = bcResponse.data.solutions[0];
|
|
12915
|
+
const variables = {};
|
|
12916
|
+
for (const binding of solution.substitution.bindings) {
|
|
12917
|
+
const varName = binding.variable_name;
|
|
12918
|
+
if (!varName) continue;
|
|
12919
|
+
const value = parseFloat(binding.bound_to_display);
|
|
12920
|
+
if (isNaN(value)) continue;
|
|
12921
|
+
if (varName.startsWith("?") && !varName.startsWith("?_lp_")) {
|
|
12922
|
+
variables[varName.slice(1)] = value;
|
|
12923
|
+
}
|
|
12924
|
+
}
|
|
12925
|
+
let objectiveValue = 0;
|
|
12926
|
+
for (const [varName, coeff] of Object.entries(problem.objective.coefficients)) {
|
|
12927
|
+
objectiveValue += coeff * (variables[varName] ?? 0);
|
|
12928
|
+
}
|
|
12929
|
+
return {
|
|
12930
|
+
status: "optimal",
|
|
12931
|
+
variables,
|
|
12932
|
+
objectiveValue,
|
|
12933
|
+
solveTimeMs: queryTimeMs
|
|
12934
|
+
};
|
|
12935
|
+
} finally {
|
|
12936
|
+
if (cleanup) {
|
|
12937
|
+
await this.cleanupArtifacts(ruleTermId, sortId);
|
|
12938
|
+
}
|
|
12939
|
+
}
|
|
12940
|
+
}
|
|
12941
|
+
/**
|
|
12942
|
+
* Solve an LP problem with variables and coefficients discovered from the knowledge base.
|
|
12943
|
+
*
|
|
12944
|
+
* @param config - Configuration specifying which sorts/features to query and how to
|
|
12945
|
+
* map them to LP variables, objective, and constraints.
|
|
12946
|
+
* @param options - Optional solver configuration.
|
|
12947
|
+
* @returns The optimization result plus the auto-generated LP and discovered terms.
|
|
12948
|
+
*
|
|
12949
|
+
* @throws {Error} If the specified sort is not found.
|
|
12950
|
+
* @throws {Error} If no terms are found for the variable sort.
|
|
12951
|
+
* @throws {Error} If a required feature is missing or non-numeric on a term.
|
|
12952
|
+
*
|
|
12953
|
+
* @remarks
|
|
12954
|
+
* This method queries existing knowledge base data to build the LP automatically:
|
|
12955
|
+
* 1. Resolves the variable sort name to its sort ID
|
|
12956
|
+
* 2. Queries all terms of that sort
|
|
12957
|
+
* 3. Extracts feature values to compute objective coefficients and constraint coefficients
|
|
12958
|
+
* 4. Builds and solves the LP
|
|
12959
|
+
*
|
|
12960
|
+
* @example
|
|
12961
|
+
* ```typescript
|
|
12962
|
+
* // Given products in the KB with features: name, profit, wood_cost, labor_cost
|
|
12963
|
+
* const result = await client.optimize.fromKnowledgeBase({
|
|
12964
|
+
* variables: { sort: 'product', nameFeature: 'name' },
|
|
12965
|
+
* objective: { direction: 'maximize', coefficientFeature: 'profit' },
|
|
12966
|
+
* resourceConstraints: [
|
|
12967
|
+
* { costFeature: 'wood_cost', capacity: 12, label: 'wood' },
|
|
12968
|
+
* { costFeature: 'labor_cost', capacity: 8, label: 'labor' },
|
|
12969
|
+
* ],
|
|
12970
|
+
* nonNegative: true,
|
|
12971
|
+
* });
|
|
12972
|
+
*
|
|
12973
|
+
* if (result.result.status === 'optimal') {
|
|
12974
|
+
* console.log(result.result.variables); // { chair: 2.4, table: 3.2 }
|
|
12975
|
+
* }
|
|
12976
|
+
* console.log(result.generatedProblem); // The auto-generated LP for inspection
|
|
12977
|
+
* ```
|
|
12978
|
+
*/
|
|
12979
|
+
async fromKnowledgeBase(config, options) {
|
|
12980
|
+
const sortId = await this.resolveSortName(config.variables.sort);
|
|
12981
|
+
const queryResponse = await this.queryApi.findBySort({
|
|
12982
|
+
sort_id: sortId
|
|
12983
|
+
});
|
|
12984
|
+
const terms = queryResponse.data.terms;
|
|
12985
|
+
if (terms.length === 0) {
|
|
12986
|
+
throw new Error(
|
|
12987
|
+
`No terms found for sort '${config.variables.sort}'. Create terms with features [${config.objective.coefficientFeature}, ${config.resourceConstraints.map((r) => r.costFeature).join(", ")}] first.`
|
|
12988
|
+
);
|
|
12989
|
+
}
|
|
12990
|
+
const variableNames = [];
|
|
12991
|
+
const objectiveCoeffs = {};
|
|
12992
|
+
const constraintCoeffsMap = {};
|
|
12993
|
+
for (const rc of config.resourceConstraints) {
|
|
12994
|
+
constraintCoeffsMap[rc.costFeature] = {};
|
|
12995
|
+
}
|
|
12996
|
+
for (const term of terms) {
|
|
12997
|
+
const name = extractStringValue(term.features, config.variables.nameFeature);
|
|
12998
|
+
if (!name) {
|
|
12999
|
+
throw new Error(
|
|
13000
|
+
`Term ${term.id} of sort '${config.variables.sort}' is missing the name feature '${config.variables.nameFeature}' or it is not a string.`
|
|
13001
|
+
);
|
|
13002
|
+
}
|
|
13003
|
+
variableNames.push(name);
|
|
13004
|
+
const objCoeff = extractNumericValue(term.features, config.objective.coefficientFeature);
|
|
13005
|
+
if (objCoeff === null) {
|
|
13006
|
+
throw new Error(
|
|
13007
|
+
`Term '${name}' (${term.id}) is missing numeric feature '${config.objective.coefficientFeature}' for the objective.`
|
|
13008
|
+
);
|
|
13009
|
+
}
|
|
13010
|
+
objectiveCoeffs[name] = objCoeff;
|
|
13011
|
+
for (const rc of config.resourceConstraints) {
|
|
13012
|
+
const costCoeff = extractNumericValue(term.features, rc.costFeature);
|
|
13013
|
+
if (costCoeff === null) {
|
|
13014
|
+
throw new Error(
|
|
13015
|
+
`Term '${name}' (${term.id}) is missing numeric feature '${rc.costFeature}' for the resource constraint.`
|
|
13016
|
+
);
|
|
13017
|
+
}
|
|
13018
|
+
constraintCoeffsMap[rc.costFeature][name] = costCoeff;
|
|
13019
|
+
}
|
|
13020
|
+
}
|
|
13021
|
+
const constraints = config.resourceConstraints.map((rc) => ({
|
|
13022
|
+
coefficients: constraintCoeffsMap[rc.costFeature],
|
|
13023
|
+
op: rc.op ?? "<=",
|
|
13024
|
+
rhs: rc.capacity,
|
|
13025
|
+
...rc.label ? { label: rc.label } : {}
|
|
13026
|
+
}));
|
|
13027
|
+
if (config.additionalConstraints) {
|
|
13028
|
+
constraints.push(...config.additionalConstraints);
|
|
13029
|
+
}
|
|
13030
|
+
const generatedProblem = {
|
|
13031
|
+
objective: {
|
|
13032
|
+
direction: config.objective.direction,
|
|
13033
|
+
coefficients: objectiveCoeffs
|
|
13034
|
+
},
|
|
13035
|
+
constraints,
|
|
13036
|
+
bounds: config.nonNegative ? Object.fromEntries(variableNames.map((n) => [n, { min: 0 }])) : void 0
|
|
13037
|
+
};
|
|
13038
|
+
const result = await this.solve(generatedProblem, options);
|
|
13039
|
+
return {
|
|
13040
|
+
result,
|
|
13041
|
+
generatedProblem,
|
|
13042
|
+
discoveredTerms: terms
|
|
13043
|
+
};
|
|
13044
|
+
}
|
|
13045
|
+
/**
|
|
13046
|
+
* Resolve a sort name to its sort ID by listing the tenant's sorts.
|
|
13047
|
+
*
|
|
13048
|
+
* @internal
|
|
13049
|
+
*/
|
|
13050
|
+
async resolveSortName(sortName) {
|
|
13051
|
+
const response = await this.sortsApi.listSorts(this.tenantId);
|
|
13052
|
+
const sorts = response.data.sorts;
|
|
13053
|
+
const match = sorts.find((s) => s.name === sortName);
|
|
13054
|
+
if (!match) {
|
|
13055
|
+
const available = sorts.slice(0, 10).map((s) => s.name).join(", ");
|
|
13056
|
+
throw new Error(
|
|
13057
|
+
`Sort '${sortName}' not found. Available sorts: ${available}${sorts.length > 10 ? "..." : ""}`
|
|
13058
|
+
);
|
|
13059
|
+
}
|
|
13060
|
+
return match.id;
|
|
13061
|
+
}
|
|
13062
|
+
/**
|
|
13063
|
+
* Clean up temporary sort and rule artifacts (best-effort).
|
|
13064
|
+
*
|
|
13065
|
+
* @internal
|
|
13066
|
+
*/
|
|
13067
|
+
async cleanupArtifacts(ruleTermId, sortId) {
|
|
13068
|
+
const promises = [];
|
|
13069
|
+
if (ruleTermId) {
|
|
13070
|
+
promises.push(
|
|
13071
|
+
this.termsApi.deleteTerm(ruleTermId).catch(() => {
|
|
13072
|
+
})
|
|
13073
|
+
);
|
|
13074
|
+
}
|
|
13075
|
+
if (sortId) {
|
|
13076
|
+
promises.push(
|
|
13077
|
+
this.sortsApi.deleteSort(sortId).catch(() => {
|
|
13078
|
+
})
|
|
13079
|
+
);
|
|
13080
|
+
}
|
|
13081
|
+
await Promise.all(promises);
|
|
13082
|
+
}
|
|
13083
|
+
};
|
|
13084
|
+
function generateShortId() {
|
|
13085
|
+
const timestamp = Date.now().toString(36);
|
|
13086
|
+
const random = Math.random().toString(36).slice(2, 8);
|
|
13087
|
+
return `${timestamp}_${random}`;
|
|
13088
|
+
}
|
|
13089
|
+
function extractStringValue(features, featureName) {
|
|
13090
|
+
const value = features[featureName];
|
|
13091
|
+
if (!value) return null;
|
|
13092
|
+
if (value.type === "String") return value.value;
|
|
13093
|
+
return null;
|
|
13094
|
+
}
|
|
13095
|
+
function extractNumericValue(features, featureName) {
|
|
13096
|
+
const value = features[featureName];
|
|
13097
|
+
if (!value) return null;
|
|
13098
|
+
if (value.type === "Integer") return value.value;
|
|
13099
|
+
if (value.type === "Real") return value.value;
|
|
13100
|
+
return null;
|
|
13101
|
+
}
|
|
13102
|
+
|
|
12549
13103
|
// src/client.ts
|
|
12550
13104
|
var ReasoningLayerClient = class {
|
|
12551
13105
|
/** Sort (type hierarchy) operations. */
|
|
@@ -12632,6 +13186,8 @@ var ReasoningLayerClient = class {
|
|
|
12632
13186
|
generation;
|
|
12633
13187
|
/** Ontology RAG operations (embedding search + feature unification). */
|
|
12634
13188
|
rag;
|
|
13189
|
+
/** Linear program optimization (CLP(Q) simplex solver via backward chaining). */
|
|
13190
|
+
optimize;
|
|
12635
13191
|
/**
|
|
12636
13192
|
* Create a new ReasoningLayerClient.
|
|
12637
13193
|
*
|
|
@@ -12734,6 +13290,7 @@ var ReasoningLayerClient = class {
|
|
|
12734
13290
|
this.ontology = new OntologyClient(generatedOntology);
|
|
12735
13291
|
this.generation = new GenerationClient(generatedGeneration);
|
|
12736
13292
|
this.rag = new RagClient(generatedRag);
|
|
13293
|
+
this.optimize = new OptimizeClient(generatedInference, generatedSorts, generatedQuery, generatedTerms, resolved.tenantId);
|
|
12737
13294
|
}
|
|
12738
13295
|
};
|
|
12739
13296
|
|
|
@@ -13602,6 +14159,6 @@ function discriminateFeatureValue(value) {
|
|
|
13602
14159
|
);
|
|
13603
14160
|
}
|
|
13604
14161
|
|
|
13605
|
-
export { ApiError, BadRequestError, ConstraintViolationError, FeatureInput, FuzzyShape, InternalServerError, NetworkError, NotFoundError, RateLimitError, ReasoningLayerClient, ReasoningLayerError, SDK_VERSION, SortBuilder, TermInput, TimeoutError, ValidationError, Value, WebSocketClient, WebSocketConnection, allen, discriminateFeatureValue, guard, isUuid, psi };
|
|
14162
|
+
export { ApiError, BadRequestError, ConstraintViolationError, FeatureInput, FuzzyShape, InternalServerError, LP, NetworkError, NotFoundError, RateLimitError, ReasoningLayerClient, ReasoningLayerError, SDK_VERSION, SortBuilder, TermInput, TimeoutError, ValidationError, Value, WebSocketClient, WebSocketConnection, allen, discriminateFeatureValue, guard, isUuid, psi };
|
|
13606
14163
|
//# sourceMappingURL=index.js.map
|
|
13607
14164
|
//# sourceMappingURL=index.js.map
|