@kortexya/reasoninglayer 0.20.0 → 0.22.0
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/dist/index.cjs +480 -3
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +779 -4
- package/dist/index.d.ts +779 -4
- package/dist/index.js +480 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/config.ts
|
|
8
|
-
var SDK_VERSION = "0.
|
|
8
|
+
var SDK_VERSION = "0.22.0";
|
|
9
9
|
function resolveConfig(config) {
|
|
10
10
|
if (!config.baseUrl) {
|
|
11
11
|
throw new Error("ClientConfig.baseUrl is required");
|
|
@@ -955,11 +955,10 @@ var Sorts = class {
|
|
|
955
955
|
...params
|
|
956
956
|
});
|
|
957
957
|
/**
|
|
958
|
-
*
|
|
958
|
+
* No description
|
|
959
959
|
*
|
|
960
960
|
* @tags sorts
|
|
961
961
|
* @name IndexSorts
|
|
962
|
-
* @summary Index all sorts for a tenant into the vector store (Qdrant).
|
|
963
962
|
* @request POST:/api/v1/sorts/index
|
|
964
963
|
* @secure
|
|
965
964
|
*/
|
|
@@ -7389,6 +7388,54 @@ var Scheduling = class {
|
|
|
7389
7388
|
constructor(http) {
|
|
7390
7389
|
this.http = http;
|
|
7391
7390
|
}
|
|
7391
|
+
/**
|
|
7392
|
+
* No description
|
|
7393
|
+
*
|
|
7394
|
+
* @tags scheduling
|
|
7395
|
+
* @name AddPin
|
|
7396
|
+
* @summary `POST /api/v1/scheduling/problems/{id}/pins`
|
|
7397
|
+
* @request POST:/api/v1/scheduling/problems/{problem_id}/pins
|
|
7398
|
+
*/
|
|
7399
|
+
addPin = (problemId, data, params = {}) => this.http.request({
|
|
7400
|
+
path: `/api/v1/scheduling/problems/${problemId}/pins`,
|
|
7401
|
+
method: "POST",
|
|
7402
|
+
body: data,
|
|
7403
|
+
type: "application/json" /* Json */,
|
|
7404
|
+
format: "json",
|
|
7405
|
+
...params
|
|
7406
|
+
});
|
|
7407
|
+
/**
|
|
7408
|
+
* No description
|
|
7409
|
+
*
|
|
7410
|
+
* @tags scheduling
|
|
7411
|
+
* @name AddPreference
|
|
7412
|
+
* @summary `POST /api/v1/scheduling/problems/{id}/preferences`
|
|
7413
|
+
* @request POST:/api/v1/scheduling/problems/{problem_id}/preferences
|
|
7414
|
+
*/
|
|
7415
|
+
addPreference = (problemId, data, params = {}) => this.http.request({
|
|
7416
|
+
path: `/api/v1/scheduling/problems/${problemId}/preferences`,
|
|
7417
|
+
method: "POST",
|
|
7418
|
+
body: data,
|
|
7419
|
+
type: "application/json" /* Json */,
|
|
7420
|
+
format: "json",
|
|
7421
|
+
...params
|
|
7422
|
+
});
|
|
7423
|
+
/**
|
|
7424
|
+
* @description Freeze the inline scheduling inputs into a `scheduling.problem` Ψ-term snapshot stored in the application-layer scheduling store, and return its ID. The endpoint does NOT solve — call `POST /api/v1/scheduling/problems/{id}/solve` to compute the optimum, then `GET /api/v1/scheduling/problems/{id}/assignments` to retrieve the per-cell trichotomy. Snapshot mode: subsequent re-solves read only the snapshot, not any source terms in the KB. This keeps the optimum reproducible and auditable from the moment the problem is created.
|
|
7425
|
+
*
|
|
7426
|
+
* @tags scheduling
|
|
7427
|
+
* @name CreateProblem
|
|
7428
|
+
* @summary `POST /api/v1/scheduling/problems`
|
|
7429
|
+
* @request POST:/api/v1/scheduling/problems
|
|
7430
|
+
*/
|
|
7431
|
+
createProblem = (data, params = {}) => this.http.request({
|
|
7432
|
+
path: `/api/v1/scheduling/problems`,
|
|
7433
|
+
method: "POST",
|
|
7434
|
+
body: data,
|
|
7435
|
+
type: "application/json" /* Json */,
|
|
7436
|
+
format: "json",
|
|
7437
|
+
...params
|
|
7438
|
+
});
|
|
7392
7439
|
/**
|
|
7393
7440
|
* @description Classify every `(agent, day, shift)` cell in the input grid as confirmed-true, confirmed-false, or free, and list the role(s) each cell could cover. Input validation errors (duplicate agent IDs, out-of-range pins, role minima exceeding total demand, pin role the agent doesn't have, pin on a multi-role agent where the role is ambiguous, etc.) return HTTP 400. Infeasibility of a well-formed problem is a valid answer and returns HTTP 200 with `status = "infeasible"` and an empty `assignments` list.
|
|
7394
7441
|
*
|
|
@@ -7405,6 +7452,90 @@ var Scheduling = class {
|
|
|
7405
7452
|
format: "json",
|
|
7406
7453
|
...params
|
|
7407
7454
|
});
|
|
7455
|
+
/**
|
|
7456
|
+
* No description
|
|
7457
|
+
*
|
|
7458
|
+
* @tags scheduling
|
|
7459
|
+
* @name GetProblem
|
|
7460
|
+
* @summary `GET /api/v1/scheduling/problems/{id}` — read the current state.
|
|
7461
|
+
* @request GET:/api/v1/scheduling/problems/{problem_id}
|
|
7462
|
+
*/
|
|
7463
|
+
getProblem = (problemId, params = {}) => this.http.request({
|
|
7464
|
+
path: `/api/v1/scheduling/problems/${problemId}`,
|
|
7465
|
+
method: "GET",
|
|
7466
|
+
format: "json",
|
|
7467
|
+
...params
|
|
7468
|
+
});
|
|
7469
|
+
/**
|
|
7470
|
+
* @description Retrieve the derived `scheduling.assignment` Ψ-terms produced by the most recent solve. Returns an empty list when the problem has never been solved, or when the problem ID isn't known for this tenant. Includes `free` cells (per the materialise decision) so consumers can residuate on them.
|
|
7471
|
+
*
|
|
7472
|
+
* @tags scheduling
|
|
7473
|
+
* @name ListAssignments
|
|
7474
|
+
* @summary `GET /api/v1/scheduling/problems/{id}/assignments`
|
|
7475
|
+
* @request GET:/api/v1/scheduling/problems/{problem_id}/assignments
|
|
7476
|
+
*/
|
|
7477
|
+
listAssignments = (problemId, params = {}) => this.http.request({
|
|
7478
|
+
path: `/api/v1/scheduling/problems/${problemId}/assignments`,
|
|
7479
|
+
method: "GET",
|
|
7480
|
+
format: "json",
|
|
7481
|
+
...params
|
|
7482
|
+
});
|
|
7483
|
+
/**
|
|
7484
|
+
* @description Same hard constraints as `/scheduling/feasibility` plus a list of soft `preferences` (each a per-cell score added to the optimizer's objective). Returns the per-cell trichotomy across the space of **optimal** schedules, plus `total_score` (sum of preference scores at chosen cells in the optimum). `confirmed_true` / `confirmed_false` here are stronger than in `/feasibility`: they hold across every optimum, not every feasible schedule. Cells with status `free` indicate ties — multiple optima exist and the cell varies between them. Preferences targeting structurally infeasible cells (agent has a day-off on the day, is restricted to a different shift, or otherwise cannot occupy the slot) are silently ignored — the preference cannot fire when the agent cannot be there. Preferences targeting **pinned** cells DO contribute to `total_score`: pins force the agent into the cell, so the preference is realised by the chosen schedule.
|
|
7485
|
+
*
|
|
7486
|
+
* @tags scheduling
|
|
7487
|
+
* @name Optimize
|
|
7488
|
+
* @summary `POST /api/v1/scheduling/optimize`
|
|
7489
|
+
* @request POST:/api/v1/scheduling/optimize
|
|
7490
|
+
*/
|
|
7491
|
+
optimize = (data, params = {}) => this.http.request({
|
|
7492
|
+
path: `/api/v1/scheduling/optimize`,
|
|
7493
|
+
method: "POST",
|
|
7494
|
+
body: data,
|
|
7495
|
+
type: "application/json" /* Json */,
|
|
7496
|
+
format: "json",
|
|
7497
|
+
...params
|
|
7498
|
+
});
|
|
7499
|
+
/**
|
|
7500
|
+
* No description
|
|
7501
|
+
*
|
|
7502
|
+
* @tags scheduling
|
|
7503
|
+
* @name RemovePin
|
|
7504
|
+
* @summary `DELETE /api/v1/scheduling/problems/{id}/pins/{pin_id}`
|
|
7505
|
+
* @request DELETE:/api/v1/scheduling/problems/{problem_id}/pins/{pin_id}
|
|
7506
|
+
*/
|
|
7507
|
+
removePin = (problemId, pinId, params = {}) => this.http.request({
|
|
7508
|
+
path: `/api/v1/scheduling/problems/${problemId}/pins/${pinId}`,
|
|
7509
|
+
method: "DELETE",
|
|
7510
|
+
...params
|
|
7511
|
+
});
|
|
7512
|
+
/**
|
|
7513
|
+
* No description
|
|
7514
|
+
*
|
|
7515
|
+
* @tags scheduling
|
|
7516
|
+
* @name RemovePreference
|
|
7517
|
+
* @summary `DELETE /api/v1/scheduling/problems/{id}/preferences/{preference_id}`
|
|
7518
|
+
* @request DELETE:/api/v1/scheduling/problems/{problem_id}/preferences/{preference_id}
|
|
7519
|
+
*/
|
|
7520
|
+
removePreference = (problemId, preferenceId, params = {}) => this.http.request({
|
|
7521
|
+
path: `/api/v1/scheduling/problems/${problemId}/preferences/${preferenceId}`,
|
|
7522
|
+
method: "DELETE",
|
|
7523
|
+
...params
|
|
7524
|
+
});
|
|
7525
|
+
/**
|
|
7526
|
+
* @description Re-solve the stored snapshot: project it back into a domain `SchedulingProblem`, run the optimizer, and lift the per-cell trichotomy into `scheduling.assignment` Ψ-terms (idempotent — previous derived assignments for this problem are replaced). Returns only `status` and `total_score`; fetch the per-cell trichotomy via `/assignments`.
|
|
7527
|
+
*
|
|
7528
|
+
* @tags scheduling
|
|
7529
|
+
* @name SolveProblem
|
|
7530
|
+
* @summary `POST /api/v1/scheduling/problems/{id}/solve`
|
|
7531
|
+
* @request POST:/api/v1/scheduling/problems/{problem_id}/solve
|
|
7532
|
+
*/
|
|
7533
|
+
solveProblem = (problemId, params = {}) => this.http.request({
|
|
7534
|
+
path: `/api/v1/scheduling/problems/${problemId}/solve`,
|
|
7535
|
+
method: "POST",
|
|
7536
|
+
format: "json",
|
|
7537
|
+
...params
|
|
7538
|
+
});
|
|
7408
7539
|
};
|
|
7409
7540
|
|
|
7410
7541
|
// src/api-spec/generated/Admin.ts
|
|
@@ -20534,6 +20665,135 @@ function SchedulingFeasibilityResponseFromApiToFront(dto) {
|
|
|
20534
20665
|
assignments: dto.assignments.map(AssignmentFromApiToFront)
|
|
20535
20666
|
};
|
|
20536
20667
|
}
|
|
20668
|
+
function PreferenceFromFrontToApi(pref) {
|
|
20669
|
+
return {
|
|
20670
|
+
agent_id: pref.agentId,
|
|
20671
|
+
day: pref.day,
|
|
20672
|
+
shift: pref.shift,
|
|
20673
|
+
score: pref.score
|
|
20674
|
+
};
|
|
20675
|
+
}
|
|
20676
|
+
function SchedulingOptimizeRequestFromFrontToApi(request) {
|
|
20677
|
+
const dto = {
|
|
20678
|
+
agents: request.agents.map(AgentSpecFromFrontToApi),
|
|
20679
|
+
days: request.days,
|
|
20680
|
+
shifts_per_day: request.shiftsPerDay,
|
|
20681
|
+
demands: request.demands.map(ShiftDemandFromFrontToApi)
|
|
20682
|
+
};
|
|
20683
|
+
if (request.pins !== void 0) {
|
|
20684
|
+
dto.pins = request.pins.map(PinFromFrontToApi);
|
|
20685
|
+
}
|
|
20686
|
+
if (request.preferences !== void 0) {
|
|
20687
|
+
dto.preferences = request.preferences.map(PreferenceFromFrontToApi);
|
|
20688
|
+
}
|
|
20689
|
+
return dto;
|
|
20690
|
+
}
|
|
20691
|
+
function SchedulingOptimizeResponseFromApiToFront(dto) {
|
|
20692
|
+
return {
|
|
20693
|
+
status: dto.status,
|
|
20694
|
+
totalScore: dto.total_score,
|
|
20695
|
+
assignments: dto.assignments.map(AssignmentFromApiToFront)
|
|
20696
|
+
};
|
|
20697
|
+
}
|
|
20698
|
+
function CreateSchedulingProblemRequestFromFrontToApi(request) {
|
|
20699
|
+
const dto = {
|
|
20700
|
+
agents: request.agents.map(AgentSpecFromFrontToApi),
|
|
20701
|
+
days: request.days,
|
|
20702
|
+
shifts_per_day: request.shiftsPerDay,
|
|
20703
|
+
demands: request.demands.map(ShiftDemandFromFrontToApi)
|
|
20704
|
+
};
|
|
20705
|
+
if (request.pins !== void 0) {
|
|
20706
|
+
dto.pins = request.pins.map(PinFromFrontToApi);
|
|
20707
|
+
}
|
|
20708
|
+
if (request.preferences !== void 0) {
|
|
20709
|
+
dto.preferences = request.preferences.map(PreferenceFromFrontToApi);
|
|
20710
|
+
}
|
|
20711
|
+
return dto;
|
|
20712
|
+
}
|
|
20713
|
+
function CreateSchedulingProblemResponseFromApiToFront(dto) {
|
|
20714
|
+
return {
|
|
20715
|
+
problemId: dto.problem_id
|
|
20716
|
+
};
|
|
20717
|
+
}
|
|
20718
|
+
function SolveSchedulingProblemResponseFromApiToFront(dto) {
|
|
20719
|
+
return {
|
|
20720
|
+
status: dto.status,
|
|
20721
|
+
totalScore: dto.total_score
|
|
20722
|
+
};
|
|
20723
|
+
}
|
|
20724
|
+
function SchedulingAssignmentsResponseFromApiToFront(dto) {
|
|
20725
|
+
return {
|
|
20726
|
+
totalScore: dto.total_score,
|
|
20727
|
+
assignments: dto.assignments.map(AssignmentFromApiToFront)
|
|
20728
|
+
};
|
|
20729
|
+
}
|
|
20730
|
+
function AddPinRequestFromFrontToApi(request) {
|
|
20731
|
+
const dto = {
|
|
20732
|
+
agent_id: request.agentId,
|
|
20733
|
+
day: request.day,
|
|
20734
|
+
shift: request.shift
|
|
20735
|
+
};
|
|
20736
|
+
if (request.role !== void 0) {
|
|
20737
|
+
dto.role = request.role;
|
|
20738
|
+
}
|
|
20739
|
+
return dto;
|
|
20740
|
+
}
|
|
20741
|
+
function AddPinResponseFromApiToFront(dto) {
|
|
20742
|
+
return {
|
|
20743
|
+
pinId: dto.pin_id,
|
|
20744
|
+
version: dto.version
|
|
20745
|
+
};
|
|
20746
|
+
}
|
|
20747
|
+
function AddPreferenceRequestFromFrontToApi(request) {
|
|
20748
|
+
return {
|
|
20749
|
+
agent_id: request.agentId,
|
|
20750
|
+
day: request.day,
|
|
20751
|
+
shift: request.shift,
|
|
20752
|
+
score: request.score
|
|
20753
|
+
};
|
|
20754
|
+
}
|
|
20755
|
+
function AddPreferenceResponseFromApiToFront(dto) {
|
|
20756
|
+
return {
|
|
20757
|
+
preferenceId: dto.preference_id,
|
|
20758
|
+
version: dto.version
|
|
20759
|
+
};
|
|
20760
|
+
}
|
|
20761
|
+
function PinEntryFromApiToFront(dto) {
|
|
20762
|
+
const entry = {
|
|
20763
|
+
pinId: dto.pin_id,
|
|
20764
|
+
agentId: dto.agent_id,
|
|
20765
|
+
day: dto.day,
|
|
20766
|
+
shift: dto.shift
|
|
20767
|
+
};
|
|
20768
|
+
if (dto.role !== void 0 && dto.role !== null) {
|
|
20769
|
+
entry.role = dto.role;
|
|
20770
|
+
}
|
|
20771
|
+
return entry;
|
|
20772
|
+
}
|
|
20773
|
+
function PreferenceEntryFromApiToFront(dto) {
|
|
20774
|
+
return {
|
|
20775
|
+
preferenceId: dto.preference_id,
|
|
20776
|
+
agentId: dto.agent_id,
|
|
20777
|
+
day: dto.day,
|
|
20778
|
+
shift: dto.shift,
|
|
20779
|
+
score: dto.score
|
|
20780
|
+
};
|
|
20781
|
+
}
|
|
20782
|
+
function SchedulingProblemFromApiToFront(dto) {
|
|
20783
|
+
const problem = {
|
|
20784
|
+
problemId: dto.problem_id,
|
|
20785
|
+
days: dto.days,
|
|
20786
|
+
shiftsPerDay: dto.shifts_per_day,
|
|
20787
|
+
version: dto.version,
|
|
20788
|
+
pins: dto.pins.map(PinEntryFromApiToFront),
|
|
20789
|
+
preferences: dto.preferences.map(PreferenceEntryFromApiToFront),
|
|
20790
|
+
totalScore: dto.total_score
|
|
20791
|
+
};
|
|
20792
|
+
if (dto.latest_solve_status !== void 0 && dto.latest_solve_status !== null) {
|
|
20793
|
+
problem.latestSolveStatus = dto.latest_solve_status;
|
|
20794
|
+
}
|
|
20795
|
+
return problem;
|
|
20796
|
+
}
|
|
20537
20797
|
|
|
20538
20798
|
// src/resources/scheduling.ts
|
|
20539
20799
|
var SchedulingClient = class {
|
|
@@ -20564,6 +20824,223 @@ var SchedulingClient = class {
|
|
|
20564
20824
|
);
|
|
20565
20825
|
return SchedulingFeasibilityResponseFromApiToFront(response.data);
|
|
20566
20826
|
}
|
|
20827
|
+
/**
|
|
20828
|
+
* Solve the scheduling problem with **soft preferences** and
|
|
20829
|
+
* return the per-cell envelope across the space of *optimal*
|
|
20830
|
+
* schedules.
|
|
20831
|
+
*
|
|
20832
|
+
* @param request - the scheduling problem plus optional
|
|
20833
|
+
* `preferences` (per-cell scores added to the optimizer's
|
|
20834
|
+
* objective). Same hard-constraint shape as
|
|
20835
|
+
* {@link SchedulingClient.feasibility}.
|
|
20836
|
+
* @returns a {@link SchedulingOptimizeResponse} with `totalScore`
|
|
20837
|
+
* and per-cell trichotomy across optimal schedules.
|
|
20838
|
+
*
|
|
20839
|
+
* @throws HTTP 400 errors are surfaced when the input is malformed
|
|
20840
|
+
* (duplicate agent IDs, pins or preferences referencing unknown
|
|
20841
|
+
* agents, ambiguous pin role on multi-role agents, role minima
|
|
20842
|
+
* exceeding total demand, etc.).
|
|
20843
|
+
*
|
|
20844
|
+
* @remarks
|
|
20845
|
+
* The trichotomy returned here is **strictly stronger** than the
|
|
20846
|
+
* one from {@link SchedulingClient.feasibility}:
|
|
20847
|
+
*
|
|
20848
|
+
* - `"confirmed_true"` — assigned in *every* optimum.
|
|
20849
|
+
* - `"confirmed_false"` — assigned in *no* optimum.
|
|
20850
|
+
* - `"free"` — varies across the optima; the optimizer is indifferent
|
|
20851
|
+
* between equally-good choices.
|
|
20852
|
+
*
|
|
20853
|
+
* `totalScore` is the sum of {@link Preference.score} over assigned
|
|
20854
|
+
* cells in the optimum (`0` when no preferences are supplied or
|
|
20855
|
+
* the problem is infeasible).
|
|
20856
|
+
*
|
|
20857
|
+
* Preferences targeting structurally-fixed cells (pinned cells,
|
|
20858
|
+
* day-off / shift-only restricted cells, agents not in the grid)
|
|
20859
|
+
* are silently ignored — the optimizer has no choice to make there.
|
|
20860
|
+
*
|
|
20861
|
+
* Empty `preferences` is equivalent to calling
|
|
20862
|
+
* {@link SchedulingClient.feasibility} (every feasible schedule
|
|
20863
|
+
* is optimal under a zero objective), but slower; prefer
|
|
20864
|
+
* `feasibility()` when you only need the feasibility envelope.
|
|
20865
|
+
*
|
|
20866
|
+
* @example Score Aisha as a strong preference for emergency cover
|
|
20867
|
+
* ```typescript
|
|
20868
|
+
* const report = await client.scheduling.optimize({
|
|
20869
|
+
* agents: [
|
|
20870
|
+
* { id: 'aisha', roles: ['icu', 'emergency'], maxAssignments: 5 },
|
|
20871
|
+
* { id: 'bob', roles: ['general'], maxAssignments: 5 },
|
|
20872
|
+
* ],
|
|
20873
|
+
* days: 7,
|
|
20874
|
+
* shiftsPerDay: 3,
|
|
20875
|
+
* demands: [{ day: 0, shift: 0, total: 2, roleMinimums: { icu: 1 } }],
|
|
20876
|
+
* preferences: [
|
|
20877
|
+
* { agentId: 'aisha', day: 0, shift: 0, score: 10 },
|
|
20878
|
+
* ],
|
|
20879
|
+
* });
|
|
20880
|
+
*
|
|
20881
|
+
* console.log(report.totalScore); // 10 if Aisha is in the optimum
|
|
20882
|
+
* console.log(report.status); // 'feasible' | 'infeasible'
|
|
20883
|
+
* ```
|
|
20884
|
+
*/
|
|
20885
|
+
async optimize(request) {
|
|
20886
|
+
const response = await this.api.optimize(
|
|
20887
|
+
SchedulingOptimizeRequestFromFrontToApi(request)
|
|
20888
|
+
);
|
|
20889
|
+
return SchedulingOptimizeResponseFromApiToFront(response.data);
|
|
20890
|
+
}
|
|
20891
|
+
// ── Snapshot-driven endpoints (POST /scheduling/problems/*) ───────
|
|
20892
|
+
/**
|
|
20893
|
+
* Freeze the inline scheduling inputs into a `scheduling.problem`
|
|
20894
|
+
* Ψ-term snapshot stored under the caller's tenant, and return the
|
|
20895
|
+
* snapshot's `problemId`. The endpoint does NOT solve — call
|
|
20896
|
+
* {@link SchedulingClient.solveProblem} afterwards to compute the
|
|
20897
|
+
* optimum, then {@link SchedulingClient.listAssignments} to fetch
|
|
20898
|
+
* the per-cell trichotomy.
|
|
20899
|
+
*
|
|
20900
|
+
* @param request - same inline shape as
|
|
20901
|
+
* {@link SchedulingClient.optimize}.
|
|
20902
|
+
* @returns the snapshot ID, useful for subsequent re-solves and
|
|
20903
|
+
* provenance lookups.
|
|
20904
|
+
* @throws HTTP 400 on malformed input (duplicate agent IDs,
|
|
20905
|
+
* ambiguous pin role, unknown pin or preference agent ID,
|
|
20906
|
+
* role minima exceeding total demand, etc.).
|
|
20907
|
+
*
|
|
20908
|
+
* @remarks
|
|
20909
|
+
* Re-solves read only the snapshot, so the optimum is reproducible
|
|
20910
|
+
* and auditable from the moment the problem is created. The
|
|
20911
|
+
* snapshot persists across solves — pin a problem once, re-solve
|
|
20912
|
+
* many times.
|
|
20913
|
+
*
|
|
20914
|
+
* @example
|
|
20915
|
+
* ```typescript
|
|
20916
|
+
* const { problemId } = await client.scheduling.createProblem({
|
|
20917
|
+
* agents: [{ id: 'alice', roles: ['icu'], maxAssignments: 3 }],
|
|
20918
|
+
* days: 7,
|
|
20919
|
+
* shiftsPerDay: 3,
|
|
20920
|
+
* demands: [{ day: 0, shift: 0, total: 1, roleMinimums: { icu: 1 } }],
|
|
20921
|
+
* preferences: [{ agentId: 'alice', day: 0, shift: 0, score: 5 }],
|
|
20922
|
+
* });
|
|
20923
|
+
* await client.scheduling.solveProblem(problemId);
|
|
20924
|
+
* const { totalScore, assignments } =
|
|
20925
|
+
* await client.scheduling.listAssignments(problemId);
|
|
20926
|
+
* ```
|
|
20927
|
+
*/
|
|
20928
|
+
async createProblem(request) {
|
|
20929
|
+
const response = await this.api.createProblem(
|
|
20930
|
+
CreateSchedulingProblemRequestFromFrontToApi(request)
|
|
20931
|
+
);
|
|
20932
|
+
return CreateSchedulingProblemResponseFromApiToFront(response.data);
|
|
20933
|
+
}
|
|
20934
|
+
/**
|
|
20935
|
+
* Re-solve a previously-stored snapshot, lift the per-cell
|
|
20936
|
+
* trichotomy into `scheduling.assignment` Ψ-terms (idempotent —
|
|
20937
|
+
* previously lifted assignments are replaced), and return the
|
|
20938
|
+
* optimum's `totalScore`.
|
|
20939
|
+
*
|
|
20940
|
+
* @param problemId - the ID returned by
|
|
20941
|
+
* {@link SchedulingClient.createProblem}.
|
|
20942
|
+
* @throws HTTP 404 when the problem doesn't exist for the caller's
|
|
20943
|
+
* tenant. HTTP 400 for malformed problem IDs.
|
|
20944
|
+
*
|
|
20945
|
+
* @remarks
|
|
20946
|
+
* Returns only `status` and `totalScore`; fetch the per-cell
|
|
20947
|
+
* trichotomy with {@link SchedulingClient.listAssignments}.
|
|
20948
|
+
* Re-running this method on the same `problemId` is safe — the
|
|
20949
|
+
* lifted assignment terms are replaced atomically.
|
|
20950
|
+
*/
|
|
20951
|
+
async solveProblem(problemId) {
|
|
20952
|
+
const response = await this.api.solveProblem(problemId);
|
|
20953
|
+
return SolveSchedulingProblemResponseFromApiToFront(response.data);
|
|
20954
|
+
}
|
|
20955
|
+
/**
|
|
20956
|
+
* Retrieve the lifted `scheduling.assignment` Ψ-terms produced by
|
|
20957
|
+
* the most recent solve.
|
|
20958
|
+
*
|
|
20959
|
+
* @param problemId - the ID returned by
|
|
20960
|
+
* {@link SchedulingClient.createProblem}.
|
|
20961
|
+
* @throws HTTP 404 when the problem doesn't exist for the caller's
|
|
20962
|
+
* tenant. HTTP 400 for malformed problem IDs.
|
|
20963
|
+
*
|
|
20964
|
+
* @remarks
|
|
20965
|
+
* Returns one entry per `(agent, day, shift)` cell — including
|
|
20966
|
+
* `free` cells, so consumers can residuate on cells the optimizer
|
|
20967
|
+
* is indifferent about. `assignments` is empty when the problem
|
|
20968
|
+
* exists but hasn't been solved yet.
|
|
20969
|
+
*
|
|
20970
|
+
* `totalScore` mirrors the most recent solve's optimum value, or
|
|
20971
|
+
* `0` when the problem hasn't been solved.
|
|
20972
|
+
*/
|
|
20973
|
+
async listAssignments(problemId) {
|
|
20974
|
+
const response = await this.api.listAssignments(problemId);
|
|
20975
|
+
return SchedulingAssignmentsResponseFromApiToFront(response.data);
|
|
20976
|
+
}
|
|
20977
|
+
// ── Mutation methods on the live problem ──────────────────────────
|
|
20978
|
+
/**
|
|
20979
|
+
* Read the current state of a stored problem — its pins,
|
|
20980
|
+
* preferences, version counter, and latest-solve metadata.
|
|
20981
|
+
*
|
|
20982
|
+
* @remarks
|
|
20983
|
+
* Pin and preference entries carry stable IDs (`pinId`,
|
|
20984
|
+
* `preferenceId`) — pass those to {@link SchedulingClient.removePin}
|
|
20985
|
+
* / {@link SchedulingClient.removePreference} to delete them.
|
|
20986
|
+
*
|
|
20987
|
+
* @throws HTTP 404 when the problem doesn't exist for the
|
|
20988
|
+
* caller's tenant.
|
|
20989
|
+
*/
|
|
20990
|
+
async getProblem(problemId) {
|
|
20991
|
+
const response = await this.api.getProblem(problemId);
|
|
20992
|
+
return SchedulingProblemFromApiToFront(response.data);
|
|
20993
|
+
}
|
|
20994
|
+
/**
|
|
20995
|
+
* Append a pin to a stored problem. Returns the pin's stable
|
|
20996
|
+
* ID and the problem's new version. Multiple pins on the same
|
|
20997
|
+
* `(agent, day, shift)` are not deduplicated server-side; if you
|
|
20998
|
+
* want at-most-one-pin-per-cell semantics, enforce it on the
|
|
20999
|
+
* client by checking the pin entries from
|
|
21000
|
+
* {@link SchedulingClient.getProblem} first.
|
|
21001
|
+
*
|
|
21002
|
+
* @throws HTTP 400 when the agent isn't on the problem's roster
|
|
21003
|
+
* or the (day, shift) is outside the grid. HTTP 404 when the
|
|
21004
|
+
* problem doesn't exist for the caller's tenant.
|
|
21005
|
+
*/
|
|
21006
|
+
async addPin(problemId, request) {
|
|
21007
|
+
const response = await this.api.addPin(
|
|
21008
|
+
problemId,
|
|
21009
|
+
AddPinRequestFromFrontToApi(request)
|
|
21010
|
+
);
|
|
21011
|
+
return AddPinResponseFromApiToFront(response.data);
|
|
21012
|
+
}
|
|
21013
|
+
/**
|
|
21014
|
+
* Remove a pin previously added via
|
|
21015
|
+
* {@link SchedulingClient.addPin}.
|
|
21016
|
+
*
|
|
21017
|
+
* @throws HTTP 404 when the problem doesn't exist for the
|
|
21018
|
+
* tenant or the `pinId` doesn't match any current pin
|
|
21019
|
+
* (already removed, stale ID).
|
|
21020
|
+
*/
|
|
21021
|
+
async removePin(problemId, pinId) {
|
|
21022
|
+
await this.api.removePin(problemId, pinId);
|
|
21023
|
+
}
|
|
21024
|
+
/**
|
|
21025
|
+
* Append a preference to a stored problem. Same return shape as
|
|
21026
|
+
* {@link SchedulingClient.addPin} — `preferenceId` is the stable
|
|
21027
|
+
* handle for removal. Multiple preferences targeting the same
|
|
21028
|
+
* cell sum on the next solve.
|
|
21029
|
+
*/
|
|
21030
|
+
async addPreference(problemId, request) {
|
|
21031
|
+
const response = await this.api.addPreference(
|
|
21032
|
+
problemId,
|
|
21033
|
+
AddPreferenceRequestFromFrontToApi(request)
|
|
21034
|
+
);
|
|
21035
|
+
return AddPreferenceResponseFromApiToFront(response.data);
|
|
21036
|
+
}
|
|
21037
|
+
/**
|
|
21038
|
+
* Remove a preference previously added via
|
|
21039
|
+
* {@link SchedulingClient.addPreference}.
|
|
21040
|
+
*/
|
|
21041
|
+
async removePreference(problemId, preferenceId) {
|
|
21042
|
+
await this.api.removePreference(problemId, preferenceId);
|
|
21043
|
+
}
|
|
20567
21044
|
};
|
|
20568
21045
|
|
|
20569
21046
|
// src/normalizers/osfql.ts
|