@ordewell/web 0.11.1 → 0.11.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/AUTHORS.md +4 -0
- package/dist/server/main.js +177 -55
- package/dist/server/main.js.map +1 -1
- package/package.json +2 -2
package/AUTHORS.md
CHANGED
|
@@ -27,6 +27,10 @@ record of who built what, rather than `git log`.
|
|
|
27
27
|
- [@haltingstate](https://github.com/haltingstate) — made the terminal UI's
|
|
28
28
|
stepper say what a saved step does next, instead of encoding it in a
|
|
29
29
|
sentinel index (#123).
|
|
30
|
+
- [@Logic769](https://github.com/Logic769) — made `/resume` an alias of
|
|
31
|
+
`/sessions` in the planner chat (#139).
|
|
32
|
+
- Hanbin Tan ([@hskl18](https://github.com/hskl18)) — documented how
|
|
33
|
+
planners and runners get their models and credentials (#140).
|
|
30
34
|
|
|
31
35
|
Thank you. Contributions are welcome — see [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
32
36
|
|
package/dist/server/main.js
CHANGED
|
@@ -407,6 +407,8 @@ var OrchestratorPool = class {
|
|
|
407
407
|
sequence = /* @__PURE__ */ new Map();
|
|
408
408
|
registry = new core.RunnerRegistry();
|
|
409
409
|
modelResolver;
|
|
410
|
+
/** A host that supplied its own resolver answers for every workspace, as a supplied probe does. */
|
|
411
|
+
suppliedModelResolver;
|
|
410
412
|
runnerInstallation;
|
|
411
413
|
/**
|
|
412
414
|
* A host that supplied its own probe (a test, or a surface that owns one).
|
|
@@ -419,11 +421,19 @@ var OrchestratorPool = class {
|
|
|
419
421
|
settingsService = new core.SettingsService();
|
|
420
422
|
plannerModelMemory = new core.PlannerModelMemory(this.settingsService);
|
|
421
423
|
/**
|
|
422
|
-
* The model a settings write picked in this daemon
|
|
423
|
-
* is otherwise inherited, and an agent
|
|
424
|
-
* found it does not plan with an inherited
|
|
424
|
+
* The model a settings write picked in this daemon, and the workspace it was
|
|
425
|
+
* picked in. The environment's model is otherwise inherited, and an agent
|
|
426
|
+
* planning only because detection found it does not plan with an inherited
|
|
427
|
+
* model it cannot be shown to run. The pick is that workspace's: another
|
|
428
|
+
* may name another account, whose catalog judges the model afresh.
|
|
425
429
|
*/
|
|
426
430
|
pickedModel;
|
|
431
|
+
/**
|
|
432
|
+
* The last planner write a route made, so each lands after the ones made
|
|
433
|
+
* before it: a switch still waiting for its catalog must not write over a
|
|
434
|
+
* pick made while it waited (ADR-0040).
|
|
435
|
+
*/
|
|
436
|
+
plannerWrites = Promise.resolve();
|
|
427
437
|
runner;
|
|
428
438
|
/** One probe per daemon, asked again whenever the runner list is refreshed (ADR-0033). */
|
|
429
439
|
codexSandbox;
|
|
@@ -438,7 +448,10 @@ var OrchestratorPool = class {
|
|
|
438
448
|
env: () => core.workspaceEnvOf(process.cwd()),
|
|
439
449
|
workspace: () => process.cwd()
|
|
440
450
|
});
|
|
441
|
-
this.
|
|
451
|
+
this.suppliedModelResolver = deps.modelResolver !== void 0;
|
|
452
|
+
this.modelResolver = deps.modelResolver ?? new core.ModelResolver(this.registry, new WebConfig(), {
|
|
453
|
+
env: async () => ({ ...process.env, ...await core.workspaceEnvOf(process.cwd()) })
|
|
454
|
+
});
|
|
442
455
|
this.codexSandbox = deps.codexSandbox ?? new core.CodexSandboxAvailability(this.registry, { spawn: child_process.spawn, fetch: globalThis.fetch }, { cwd: process.cwd(), env: process.env });
|
|
443
456
|
this.leaseHost = deps.leaseHost;
|
|
444
457
|
this.isolationPreview = deps.isolationPreview ?? core.createIsolationPreview({ config: new WebConfig() });
|
|
@@ -618,7 +631,7 @@ var OrchestratorPool = class {
|
|
|
618
631
|
core.ensureStateDirIgnored(workspace);
|
|
619
632
|
core.assertWorkspaceIsProject(workspace);
|
|
620
633
|
}
|
|
621
|
-
const config = this.plannerConfig(modelOverride);
|
|
634
|
+
const config = this.plannerConfig(modelOverride, workspace);
|
|
622
635
|
const fsAdapter = new PoolFileSystem(workspace);
|
|
623
636
|
const broadcast = (msg) => this.broadcast(sessionId, msg);
|
|
624
637
|
const runner = new PoolAwareRunner(sessionId, broadcast, this.runner);
|
|
@@ -637,7 +650,7 @@ var OrchestratorPool = class {
|
|
|
637
650
|
broadcast,
|
|
638
651
|
// The notification channel above is silent here; this is how a client hears how the run isolates.
|
|
639
652
|
onNotice: (notice) => this.broadcast(sessionId, notice),
|
|
640
|
-
modelResolver: this.
|
|
653
|
+
modelResolver: this.resolverFor(workspace),
|
|
641
654
|
settings: () => this.runtimeSettings(),
|
|
642
655
|
sessionId,
|
|
643
656
|
...this.leaseHost ? { leaseHost: this.leaseHost } : {}
|
|
@@ -650,13 +663,13 @@ var OrchestratorPool = class {
|
|
|
650
663
|
* lists are handed over as a reader, not a snapshot, so a credential change
|
|
651
664
|
* reaches a session that is already open.
|
|
652
665
|
*/
|
|
653
|
-
plannerConfig(modelOverride) {
|
|
666
|
+
plannerConfig(modelOverride, workspace, catalog = (provider) => this.plannerCatalogFor(provider, workspace)) {
|
|
654
667
|
return new WebConfig({
|
|
655
668
|
enabledRunners: this.enabledRunnerOverride(),
|
|
656
669
|
modelOverride,
|
|
657
670
|
providerModelLists: () => this.cachedProviderLists,
|
|
658
|
-
pickedModel: () => this.pickedModel,
|
|
659
|
-
agentCatalog: (provider) =>
|
|
671
|
+
pickedModel: () => this.pickedModel?.workspace === workspaceKey(workspace) ? this.pickedModel : void 0,
|
|
672
|
+
agentCatalog: (provider) => catalog(provider).map((model) => model.id)
|
|
660
673
|
});
|
|
661
674
|
}
|
|
662
675
|
/**
|
|
@@ -679,8 +692,13 @@ var OrchestratorPool = class {
|
|
|
679
692
|
return enabled ? current.includes(id) ? current : [...current, id] : current.filter((r) => r !== id);
|
|
680
693
|
});
|
|
681
694
|
}
|
|
682
|
-
|
|
683
|
-
|
|
695
|
+
/**
|
|
696
|
+
* What `sessionId`, or a client in `workspace`, plans with: the planner's
|
|
697
|
+
* model is judged against that workspace's runner catalog (see
|
|
698
|
+
* {@link settingsWorkspace}).
|
|
699
|
+
*/
|
|
700
|
+
getSettings(sessionId, workspace) {
|
|
701
|
+
const config = this.plannerConfig(void 0, this.settingsWorkspace(sessionId, workspace));
|
|
684
702
|
const userSettings = this.settingsService.getAll();
|
|
685
703
|
const live = sessionId ? this.sessions.get(sessionId) : void 0;
|
|
686
704
|
return {
|
|
@@ -709,45 +727,106 @@ var OrchestratorPool = class {
|
|
|
709
727
|
* they were opened with. Throws a {@link RunSettingsError}, saving nothing,
|
|
710
728
|
* for a value out of range.
|
|
711
729
|
*/
|
|
712
|
-
updateRunSettings(changes, sessionId) {
|
|
730
|
+
updateRunSettings(changes, sessionId, workspace) {
|
|
713
731
|
this.settingsService.updateRunSettings(changes);
|
|
714
732
|
if (sessionId) this.sessions.get(sessionId)?.applyRunSettings(changes);
|
|
715
|
-
return this.getSettings(sessionId);
|
|
733
|
+
return this.getSettings(sessionId, workspace);
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* The workspace whose runner catalog a settings read or write is judged
|
|
737
|
+
* against: an open session's own, else the one the client says it is in.
|
|
738
|
+
* Without either the daemon's cwd stands in. One daemon serves several
|
|
739
|
+
* workspaces, and each may name another Claude account in its environment.
|
|
740
|
+
*/
|
|
741
|
+
settingsWorkspace(sessionId, workspace) {
|
|
742
|
+
return (sessionId ? this.sessions.get(sessionId)?.workspaceRoot : void 0) ?? workspace;
|
|
716
743
|
}
|
|
717
744
|
/**
|
|
718
745
|
* The catalog `selectPlanner` should judge `provider`'s
|
|
719
746
|
* remembered model against — a harness planner's own runner catalog, or the
|
|
720
747
|
* cross-provider picker list for a vendor (ADR-0009), same split as
|
|
721
748
|
* `plannerModelItems` in the TUI reducer. Read from whatever the resolver
|
|
722
|
-
* has already cached so this stays synchronous;
|
|
723
|
-
*
|
|
749
|
+
* has already cached so this stays synchronous; the routes discover it
|
|
750
|
+
* first where it decides the answer ({@link discoverPlannerCatalogs},
|
|
751
|
+
* {@link writeSettings}), and a catalog still cold degrades to an empty one
|
|
752
|
+
* rather than kicking off discovery mid-settings-write.
|
|
724
753
|
*/
|
|
725
|
-
plannerCatalogFor(provider) {
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
754
|
+
plannerCatalogFor(provider, workspace) {
|
|
755
|
+
return this.resolverFor(workspace).cachedPlannerCatalog(provider);
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Discover the runner catalog a settings read for `workspace` is judged
|
|
759
|
+
* against, when the read consults one not yet held. Most reads consult
|
|
760
|
+
* none — a vendor planner, a model picked in that workspace, an agent's
|
|
761
|
+
* alias or remembered pick — and answer at once, however slow the runner
|
|
762
|
+
* is to list its models (ADR-0040). Only a configured model whose owner
|
|
763
|
+
* only the catalog can tell waits: a cold one would report the wrong model.
|
|
764
|
+
* Never throws: a catalog that cannot be discovered stays empty.
|
|
765
|
+
*/
|
|
766
|
+
async discoverPlannerCatalogs(sessionId, requestWorkspace) {
|
|
767
|
+
const workspace = this.settingsWorkspace(sessionId, requestWorkspace);
|
|
768
|
+
const consulted = [];
|
|
769
|
+
void this.plannerConfig(void 0, workspace, (provider) => {
|
|
770
|
+
consulted.push(provider);
|
|
771
|
+
return this.plannerCatalogFor(provider, workspace);
|
|
772
|
+
}).planner;
|
|
773
|
+
await this.discoverUnheld(workspace, consulted);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* {@link updateSettings} as a route makes it. A write that changes who plans
|
|
777
|
+
* lands after the planner writes made before it and, where its judgement
|
|
778
|
+
* reads a catalog not yet held, waits for that one; every other write — a
|
|
779
|
+
* key, an allowlist, a limit — lands at once (ADR-0040).
|
|
780
|
+
*/
|
|
781
|
+
async writeSettings(changes, sessionId, requestWorkspace) {
|
|
782
|
+
const change = plannerChangeOf(changes, admittedEnv(changes)?.accepted);
|
|
783
|
+
if (!changesPlanner(change)) return this.updateSettings(changes, sessionId, requestWorkspace);
|
|
784
|
+
const turn = this.plannerWrites.then(async () => {
|
|
785
|
+
const workspace = this.settingsWorkspace(sessionId, requestWorkspace);
|
|
786
|
+
const judging = this.catalogJudging(change, workspace);
|
|
787
|
+
await this.discoverUnheld(workspace, judging ? [judging] : []);
|
|
788
|
+
return this.updateSettings(changes, sessionId, requestWorkspace);
|
|
789
|
+
});
|
|
790
|
+
this.plannerWrites = turn.catch(() => void 0);
|
|
791
|
+
return turn;
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* The provider whose catalog `selectPlanner` reads to judge `change`: a
|
|
795
|
+
* switch with no model of its own restores the remembered pick only from
|
|
796
|
+
* the incoming catalog, and an agent's effort alone survives only where its
|
|
797
|
+
* model in effect offers it. An explicit model is the user's word whatever
|
|
798
|
+
* the catalog lists, and a cold catalog refuses no effort, so it reads none.
|
|
799
|
+
*/
|
|
800
|
+
catalogJudging(change, workspace) {
|
|
801
|
+
const current = this.plannerProviderInEffect(workspace);
|
|
802
|
+
const provider = change.provider ?? current;
|
|
803
|
+
const model = change.model?.trim();
|
|
804
|
+
if (provider !== current) return model ? void 0 : provider;
|
|
805
|
+
return model === void 0 && change.effort !== void 0 && core.runnerForProvider(provider) ? provider : void 0;
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Discover the catalogs of `providers` that `workspace`'s resolver does not
|
|
809
|
+
* hold yet; a held one, or a degraded one discovery still remembers,
|
|
810
|
+
* answers at once. Never throws.
|
|
811
|
+
*/
|
|
812
|
+
async discoverUnheld(workspace, providers) {
|
|
813
|
+
const resolver = this.resolverFor(workspace);
|
|
814
|
+
await Promise.all([...new Set(providers)].map((provider) => resolver.plannerCatalog(provider)));
|
|
731
815
|
}
|
|
732
816
|
/**
|
|
733
817
|
* The provider planning right now. A vendor planner is resolved from its
|
|
734
818
|
* model id, so this is read again after a write rather than carried over.
|
|
735
819
|
*/
|
|
736
|
-
plannerProviderInEffect() {
|
|
737
|
-
return this.plannerConfig().aiProvider;
|
|
820
|
+
plannerProviderInEffect(workspace) {
|
|
821
|
+
return this.plannerConfig(void 0, workspace).aiProvider;
|
|
738
822
|
}
|
|
739
|
-
updateSettings(changes, sessionId) {
|
|
740
|
-
const
|
|
741
|
-
const
|
|
742
|
-
const admission =
|
|
823
|
+
updateSettings(changes, sessionId, requestWorkspace) {
|
|
824
|
+
const workspace = this.settingsWorkspace(sessionId, requestWorkspace);
|
|
825
|
+
const current = this.plannerConfig(void 0, workspace).planner;
|
|
826
|
+
const admission = admittedEnv(changes);
|
|
743
827
|
const envChanges = admission ? admission.accepted : void 0;
|
|
744
|
-
const plannerChange = changes
|
|
745
|
-
|
|
746
|
-
model: envChanges?.ORCHESTRATOR_MODEL ?? stringField(changes.orchestratorModel),
|
|
747
|
-
effort: envChanges?.ORDEWELL_PLANNER_EFFORT ?? stringField(changes.plannerThinkingEffort)
|
|
748
|
-
};
|
|
749
|
-
const touchesPlanner = Object.values(plannerChange).some((v) => v !== void 0);
|
|
750
|
-
const selection = touchesPlanner ? core.selectPlanner(current, plannerChange, this.plannerModelMemory, this.plannerCatalogFor(plannerChange.provider ?? current.provider)) : void 0;
|
|
828
|
+
const plannerChange = plannerChangeOf(changes, envChanges);
|
|
829
|
+
const selection = changesPlanner(plannerChange) ? core.selectPlanner(current, plannerChange, this.plannerModelMemory, this.plannerCatalogFor(plannerChange.provider ?? current.provider, workspace)) : void 0;
|
|
751
830
|
if (envChanges) {
|
|
752
831
|
let touched = false;
|
|
753
832
|
for (const [key, value] of Object.entries(envChanges)) {
|
|
@@ -763,14 +842,15 @@ var OrchestratorPool = class {
|
|
|
763
842
|
}
|
|
764
843
|
if (touched) {
|
|
765
844
|
this.modelResolver.invalidate();
|
|
766
|
-
this.modelResolver.refreshRunnerModels();
|
|
767
845
|
this.dropUnkeyedProviderLists();
|
|
768
846
|
}
|
|
769
847
|
}
|
|
770
848
|
if (selection) {
|
|
771
849
|
if (plannerChange.provider !== void 0 || plannerChange.model !== void 0) process.env.ORCHESTRATOR_MODEL = selection.next.model;
|
|
772
850
|
process.env.ORDEWELL_PLANNER_EFFORT = selection.next.effort;
|
|
773
|
-
if (plannerChange.model !== void 0)
|
|
851
|
+
if (plannerChange.model !== void 0) {
|
|
852
|
+
this.pickedModel = { model: selection.next.model, provider: this.plannerProviderInEffect(workspace), workspace: workspaceKey(workspace) };
|
|
853
|
+
}
|
|
774
854
|
}
|
|
775
855
|
if (changes.modelAllowlist && typeof changes.modelAllowlist === "object") {
|
|
776
856
|
const allowlist = changes.modelAllowlist;
|
|
@@ -786,10 +866,10 @@ var OrchestratorPool = class {
|
|
|
786
866
|
if (selection?.remember) {
|
|
787
867
|
const { provider, model, effort } = selection.remember;
|
|
788
868
|
const switched = provider !== current.provider;
|
|
789
|
-
this.plannerModelMemory.remember(switched ? provider : this.plannerProviderInEffect(), model, effort);
|
|
869
|
+
this.plannerModelMemory.remember(switched ? provider : this.plannerProviderInEffect(workspace), model, effort);
|
|
790
870
|
}
|
|
791
871
|
const rejectedEnvKeys = admission?.rejected ?? [];
|
|
792
|
-
const settings = this.getSettings(sessionId);
|
|
872
|
+
const settings = this.getSettings(sessionId, workspace);
|
|
793
873
|
if (rejectedEnvKeys.length > 0) settings.rejectedEnvKeys = rejectedEnvKeys;
|
|
794
874
|
if (selection?.recall) settings.switchRecall = selection.recall;
|
|
795
875
|
return settings;
|
|
@@ -812,16 +892,22 @@ var OrchestratorPool = class {
|
|
|
812
892
|
process.env.ORCHESTRATOR_MODEL = model;
|
|
813
893
|
return model;
|
|
814
894
|
}
|
|
815
|
-
|
|
895
|
+
/**
|
|
896
|
+
* The catalog as `workspace`'s runners see it: Claude Code's picker lineup
|
|
897
|
+
* follows the `CLAUDE_CONFIG_DIR` that workspace's environment sets.
|
|
898
|
+
* Without a workspace the daemon's cwd stands in.
|
|
899
|
+
*/
|
|
900
|
+
async getProviderModels(workspace) {
|
|
816
901
|
const config = new WebConfig();
|
|
902
|
+
const resolver = this.resolverFor(workspace);
|
|
817
903
|
const runnerIds = this.registry.list().map((p) => p.manifest.name);
|
|
818
904
|
const [runnerModels, providerLists] = await Promise.all([
|
|
819
|
-
|
|
820
|
-
|
|
905
|
+
resolver.modelsForRunners(runnerIds),
|
|
906
|
+
resolver.refresh(),
|
|
821
907
|
this.codexSandbox.ensure()
|
|
822
908
|
]);
|
|
823
|
-
const orchestratorModels = await
|
|
824
|
-
const providerErrors =
|
|
909
|
+
const orchestratorModels = await resolver.pickerOptions();
|
|
910
|
+
const providerErrors = resolver.getDiscoveryErrors();
|
|
825
911
|
this.cachedProviderLists = providerLists;
|
|
826
912
|
const allModels = [];
|
|
827
913
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -840,16 +926,28 @@ var OrchestratorPool = class {
|
|
|
840
926
|
models: allModels,
|
|
841
927
|
modelsByRunner,
|
|
842
928
|
modesByRunner: core.runnerModesFrom(this.registry, runnerIds),
|
|
843
|
-
orchestratorModel: this.plannerConfig().orchestratorModel,
|
|
929
|
+
orchestratorModel: this.plannerConfig(void 0, workspace).orchestratorModel,
|
|
844
930
|
providers,
|
|
845
931
|
orchestratorModels,
|
|
846
932
|
providerErrors
|
|
847
933
|
};
|
|
848
934
|
}
|
|
849
|
-
getRunnerState() {
|
|
850
|
-
const config = this.plannerConfig();
|
|
935
|
+
getRunnerState(workspace) {
|
|
936
|
+
const config = this.plannerConfig(void 0, workspace);
|
|
851
937
|
return { enabledRunners: config.enabledRunners, orchestratorModel: config.orchestratorModel };
|
|
852
938
|
}
|
|
939
|
+
/**
|
|
940
|
+
* The resolver whose runner catalogs are discovered under `workspace`'s
|
|
941
|
+
* environment, the one its tasks are launched with. Kept per workspace,
|
|
942
|
+
* since one daemon serves several and a catalog is cached until refreshed;
|
|
943
|
+
* the vendor catalogs are shared by all of them.
|
|
944
|
+
*/
|
|
945
|
+
resolverFor(workspace) {
|
|
946
|
+
if (this.suppliedModelResolver || !workspace) return this.modelResolver;
|
|
947
|
+
const key = workspaceKey(workspace);
|
|
948
|
+
if (key === workspaceKey(void 0)) return this.modelResolver;
|
|
949
|
+
return this.modelResolver.withRunnerEnv(key, async () => ({ ...process.env, ...await core.workspaceEnvOf(key) }));
|
|
950
|
+
}
|
|
853
951
|
/**
|
|
854
952
|
* The probe that judges a login for `workspace`, cached so its install and
|
|
855
953
|
* auth verdicts survive between runner-list refreshes. Without a workspace
|
|
@@ -1079,9 +1177,26 @@ function getSessionList(workspace) {
|
|
|
1079
1177
|
function removeSession(sessionId, workspace) {
|
|
1080
1178
|
return core.deleteSession(sessionId, workspace);
|
|
1081
1179
|
}
|
|
1180
|
+
function admittedEnv(changes) {
|
|
1181
|
+
const raw = changes.env;
|
|
1182
|
+
return raw && typeof raw === "object" && !Array.isArray(raw) ? core.admitSettingsEnv(raw) : void 0;
|
|
1183
|
+
}
|
|
1184
|
+
function plannerChangeOf(changes, envChanges) {
|
|
1185
|
+
return changes.inherited === true ? {} : {
|
|
1186
|
+
provider: envChanges?.AI_PROVIDER,
|
|
1187
|
+
model: envChanges?.ORCHESTRATOR_MODEL ?? stringField(changes.orchestratorModel),
|
|
1188
|
+
effort: envChanges?.ORDEWELL_PLANNER_EFFORT ?? stringField(changes.plannerThinkingEffort)
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
function changesPlanner(change) {
|
|
1192
|
+
return Object.values(change).some((v) => v !== void 0);
|
|
1193
|
+
}
|
|
1082
1194
|
function stringField(value) {
|
|
1083
1195
|
return typeof value === "string" ? value : void 0;
|
|
1084
1196
|
}
|
|
1197
|
+
function workspaceKey(workspace) {
|
|
1198
|
+
return path.resolve(workspace ?? process.cwd());
|
|
1199
|
+
}
|
|
1085
1200
|
var InvalidBodyError = class extends Error {
|
|
1086
1201
|
constructor(message) {
|
|
1087
1202
|
super(message);
|
|
@@ -1224,7 +1339,7 @@ function plansRoute(pool2) {
|
|
|
1224
1339
|
const queryRunners = c.req.query("runners");
|
|
1225
1340
|
const runnerList = Array.isArray(runners) ? runners : runners ? [runners] : queryRunners ? queryRunners.split(",").map((s) => s.trim()).filter(Boolean) : void 0;
|
|
1226
1341
|
const plan = await pool2.generatePlan(c.req.param("sessionId"), goal, runnerList, ws, model, { allowInit });
|
|
1227
|
-
const { models, modelsByRunner } = await pool2.getProviderModels();
|
|
1342
|
+
const { models, modelsByRunner } = await pool2.getProviderModels(ws);
|
|
1228
1343
|
const notes = (pool2.session(c.req.param("sessionId")).planState?.conversationHistory ?? []).filter((e) => e.kind === "system").map((e) => e.content);
|
|
1229
1344
|
return c.json({ plan: core.surfacePlanState(plan), models, modelsByRunner, ...notes.length > 0 ? { notes } : {} });
|
|
1230
1345
|
} catch (err) {
|
|
@@ -1483,8 +1598,10 @@ function plansRoute(pool2) {
|
|
|
1483
1598
|
function runnersRoute(pool2) {
|
|
1484
1599
|
const router = new hono.Hono();
|
|
1485
1600
|
router.get("/", async (c) => {
|
|
1486
|
-
const
|
|
1487
|
-
const
|
|
1601
|
+
const workspace = c.req.query("workspace");
|
|
1602
|
+
const runners = await pool2.getInstalledRunners(workspace);
|
|
1603
|
+
await pool2.discoverPlannerCatalogs(void 0, workspace);
|
|
1604
|
+
const state = pool2.getRunnerState(workspace);
|
|
1488
1605
|
return c.json({
|
|
1489
1606
|
runners,
|
|
1490
1607
|
orchestratorModel: state.orchestratorModel
|
|
@@ -1507,7 +1624,7 @@ function runnersRoute(pool2) {
|
|
|
1507
1624
|
function modelsRoute(pool2) {
|
|
1508
1625
|
const router = new hono.Hono();
|
|
1509
1626
|
router.get("/", async (c) => {
|
|
1510
|
-
const result = await pool2.getProviderModels();
|
|
1627
|
+
const result = await pool2.getProviderModels(c.req.query("workspace"));
|
|
1511
1628
|
return c.json(result);
|
|
1512
1629
|
});
|
|
1513
1630
|
return router;
|
|
@@ -1572,29 +1689,34 @@ function settingsRoute(pool2) {
|
|
|
1572
1689
|
const router = new hono.Hono();
|
|
1573
1690
|
router.get("/", async (c) => {
|
|
1574
1691
|
await core.installedPlannerDetected();
|
|
1575
|
-
const
|
|
1692
|
+
const sessionId = c.req.query("sessionId") || void 0;
|
|
1693
|
+
const workspace = c.req.query("workspace") || void 0;
|
|
1694
|
+
await pool2.discoverPlannerCatalogs(sessionId, workspace);
|
|
1695
|
+
const settings = pool2.getSettings(sessionId, workspace);
|
|
1576
1696
|
return c.json(settings);
|
|
1577
1697
|
});
|
|
1578
1698
|
router.patch("/", async (c) => {
|
|
1579
1699
|
try {
|
|
1580
1700
|
await core.installedPlannerDetected();
|
|
1581
1701
|
const body = await jsonObject(c);
|
|
1582
|
-
if (Object.keys(body).
|
|
1702
|
+
if (Object.keys(body).every((key) => key === "workspace")) {
|
|
1583
1703
|
return refuse(c, 400, "At least one setting field is required");
|
|
1584
1704
|
}
|
|
1585
|
-
const { run: run2, sessionId: namedSession, ...rest } = body;
|
|
1705
|
+
const { run: run2, sessionId: namedSession, workspace: namedWorkspace, ...rest } = body;
|
|
1586
1706
|
if (namedSession !== void 0 && typeof namedSession !== "string") return refuse(c, 400, "sessionId must be a string");
|
|
1707
|
+
if (namedWorkspace !== void 0 && typeof namedWorkspace !== "string") return refuse(c, 400, "workspace must be a string");
|
|
1587
1708
|
const sessionId = namedSession || void 0;
|
|
1709
|
+
const workspace = namedWorkspace || void 0;
|
|
1588
1710
|
if (run2 !== void 0) {
|
|
1589
1711
|
if (!run2 || typeof run2 !== "object" || Array.isArray(run2)) return refuse(c, 400, "run must be an object of run settings");
|
|
1590
1712
|
try {
|
|
1591
|
-
pool2.updateRunSettings(run2, sessionId);
|
|
1713
|
+
pool2.updateRunSettings(run2, sessionId, workspace);
|
|
1592
1714
|
} catch (err) {
|
|
1593
1715
|
if (err instanceof core.RunSettingsError) return refuse(c, 400, err.message);
|
|
1594
1716
|
throw err;
|
|
1595
1717
|
}
|
|
1596
1718
|
}
|
|
1597
|
-
const result = Object.keys(rest).length > 0 ?
|
|
1719
|
+
const result = Object.keys(rest).length > 0 ? await pool2.writeSettings(rest, sessionId, workspace) : pool2.getSettings(sessionId, workspace);
|
|
1598
1720
|
return c.json(result);
|
|
1599
1721
|
} catch (err) {
|
|
1600
1722
|
return failure(c, err, "settings update", { fallback: 400 });
|