@linkshell/host 0.4.90 → 0.4.92
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/host/src/drivers/codex/driver.d.ts +5 -1
- package/dist/host/src/drivers/codex/driver.js +66 -26
- package/dist/host/src/drivers/codex/driver.js.map +1 -1
- package/dist/host/src/machine-metrics.d.ts +9 -1
- package/dist/host/src/machine-metrics.js +46 -3
- package/dist/host/src/machine-metrics.js.map +1 -1
- package/dist/host/tsconfig.tsbuildinfo +1 -1
- package/dist/wire/src/model.d.ts +21 -0
- package/dist/wire/src/model.js +10 -0
- package/dist/wire/src/model.js.map +1 -1
- package/dist/wire/src/rpc.d.ts +14 -0
- package/package.json +3 -3
|
@@ -95,6 +95,8 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
95
95
|
private readonly goalRevision;
|
|
96
96
|
private skillsRevision;
|
|
97
97
|
private models?;
|
|
98
|
+
private modelsLoadedAt?;
|
|
99
|
+
private lastModels;
|
|
98
100
|
private restartTimer?;
|
|
99
101
|
private restartDelay;
|
|
100
102
|
private stopped;
|
|
@@ -268,12 +270,14 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
268
270
|
private sideUpdate;
|
|
269
271
|
private markFullAccess;
|
|
270
272
|
private approvePending;
|
|
271
|
-
/**
|
|
273
|
+
/** Refresh when a client opens the picker; a long-running host must pick up models added since its first session. */
|
|
272
274
|
listModels(cwd?: string, model?: string): Promise<import("@linkshell/wire").MethodResult<"agents.models">>;
|
|
273
275
|
/** The model config.toml (with the project's own layers, for `cwd`) gives a new thread; undefined: Codex's default. */
|
|
274
276
|
private configuredSettings;
|
|
275
277
|
private loadModels;
|
|
276
278
|
private announceConfig;
|
|
279
|
+
private clearModels;
|
|
280
|
+
private publishConfig;
|
|
277
281
|
private isNews;
|
|
278
282
|
private loadSkills;
|
|
279
283
|
/** What `/` offers on a device: the commands above, then the skills this project can use. */
|
|
@@ -172,6 +172,8 @@ export class CodexDriver {
|
|
|
172
172
|
goalRevision = new Map();
|
|
173
173
|
skillsRevision = 0;
|
|
174
174
|
models;
|
|
175
|
+
modelsLoadedAt;
|
|
176
|
+
lastModels = [];
|
|
175
177
|
restartTimer;
|
|
176
178
|
restartDelay;
|
|
177
179
|
stopped = false;
|
|
@@ -257,6 +259,7 @@ export class CodexDriver {
|
|
|
257
259
|
clearTimeout(timer);
|
|
258
260
|
this.taskPolls.clear();
|
|
259
261
|
this.stopped = true;
|
|
262
|
+
this.clearModels();
|
|
260
263
|
if (this.restartTimer)
|
|
261
264
|
clearTimeout(this.restartTimer);
|
|
262
265
|
for (const timer of this.followRetries.values())
|
|
@@ -888,6 +891,10 @@ export class CodexDriver {
|
|
|
888
891
|
watched(nativeId, open) {
|
|
889
892
|
if (open) {
|
|
890
893
|
this.watching.add(nativeId);
|
|
894
|
+
// The hub can keep a session attached after its last viewer leaves.
|
|
895
|
+
// Reopening it must also refresh the choices sent in ls_config.
|
|
896
|
+
if (this.attached.has(nativeId) || this.observed.has(nativeId))
|
|
897
|
+
void this.announceConfig(nativeId);
|
|
891
898
|
void this.syncTasks(nativeId);
|
|
892
899
|
this.cancelRelease(nativeId);
|
|
893
900
|
}
|
|
@@ -1601,9 +1608,9 @@ export class CodexDriver {
|
|
|
1601
1608
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_permission_resolved", requestId, optionId });
|
|
1602
1609
|
}
|
|
1603
1610
|
}
|
|
1604
|
-
/**
|
|
1611
|
+
/** Refresh when a client opens the picker; a long-running host must pick up models added since its first session. */
|
|
1605
1612
|
async listModels(cwd, model) {
|
|
1606
|
-
const [models, configured] = await Promise.all([this.loadModels(true), this.configuredSettings(cwd)]);
|
|
1613
|
+
const [models, configured] = await Promise.all([this.loadModels(true, true), this.configuredSettings(cwd)]);
|
|
1607
1614
|
const listed = newThreadModels(models, configured.model);
|
|
1608
1615
|
const selected = model && listed.models.some((entry) => entry.value === model) ? model : undefined;
|
|
1609
1616
|
return { ...listed, config: configOptions(configured, selected ? { model: selected } : {}, models).filter((option) => option.category === "mode" || option.category === "effort") };
|
|
@@ -1620,33 +1627,66 @@ export class CodexDriver {
|
|
|
1620
1627
|
return {};
|
|
1621
1628
|
}
|
|
1622
1629
|
}
|
|
1623
|
-
loadModels(strict = false) {
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
let cursor;
|
|
1628
|
-
do {
|
|
1629
|
-
const result = await this.rpc("model/list", { includeHidden: false, ...(cursor ? { cursor } : {}) });
|
|
1630
|
-
models.push(...result.data);
|
|
1631
|
-
cursor = result.nextCursor ?? undefined;
|
|
1632
|
-
if (cursor && cursors.has(cursor))
|
|
1633
|
-
throw new Error("Codex 返回了重复的模型分页,请重试");
|
|
1634
|
-
if (cursor)
|
|
1635
|
-
cursors.add(cursor);
|
|
1636
|
-
} while (cursor);
|
|
1637
|
-
return models;
|
|
1638
|
-
})()
|
|
1639
|
-
.catch((error) => {
|
|
1630
|
+
loadModels(strict = false, refresh = false) {
|
|
1631
|
+
// Concurrent pickers share the same request. Internal configuration updates can
|
|
1632
|
+
// reuse its result, while the next explicit listing reads the agent again.
|
|
1633
|
+
if (this.modelsLoadedAt !== undefined && (refresh || Date.now() - this.modelsLoadedAt >= 60_000))
|
|
1640
1634
|
this.models = undefined;
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1635
|
+
if (!this.models) {
|
|
1636
|
+
this.modelsLoadedAt = undefined;
|
|
1637
|
+
const loading = (async () => {
|
|
1638
|
+
const models = [];
|
|
1639
|
+
const cursors = new Set();
|
|
1640
|
+
let cursor;
|
|
1641
|
+
do {
|
|
1642
|
+
const result = await this.rpc("model/list", { includeHidden: false, ...(cursor ? { cursor } : {}) });
|
|
1643
|
+
models.push(...result.data);
|
|
1644
|
+
cursor = result.nextCursor ?? undefined;
|
|
1645
|
+
if (cursor && cursors.has(cursor))
|
|
1646
|
+
throw new Error("Codex 返回了重复的模型分页,请重试");
|
|
1647
|
+
if (cursor)
|
|
1648
|
+
cursors.add(cursor);
|
|
1649
|
+
} while (cursor);
|
|
1650
|
+
return models;
|
|
1651
|
+
})()
|
|
1652
|
+
.then((models) => {
|
|
1653
|
+
if (this.models === loading) {
|
|
1654
|
+
this.modelsLoadedAt = Date.now();
|
|
1655
|
+
this.lastModels = models;
|
|
1656
|
+
// An existing composer reads ls_config, not agents.models. Keep its
|
|
1657
|
+
// current selection while publishing newly discovered choices.
|
|
1658
|
+
for (const nativeId of this.watching) {
|
|
1659
|
+
if (this.attached.has(nativeId) || this.observed.has(nativeId))
|
|
1660
|
+
this.publishConfig(nativeId, models);
|
|
1661
|
+
}
|
|
1662
|
+
}
|
|
1663
|
+
return models;
|
|
1664
|
+
})
|
|
1665
|
+
.catch((error) => {
|
|
1666
|
+
if (this.models === loading)
|
|
1667
|
+
this.models = undefined;
|
|
1668
|
+
this.host?.log(`[codex] model/list failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
1669
|
+
if (error instanceof RpcError && error.code === RPC_METHOD_NOT_FOUND)
|
|
1670
|
+
return [];
|
|
1671
|
+
throw error;
|
|
1672
|
+
});
|
|
1673
|
+
this.models = loading;
|
|
1674
|
+
}
|
|
1675
|
+
return strict ? this.models : this.models.catch(() => this.lastModels);
|
|
1647
1676
|
}
|
|
1648
1677
|
async announceConfig(nativeId) {
|
|
1678
|
+
// Permissions and Plan still come from this session when the catalogue
|
|
1679
|
+
// is unavailable; keep its last model choices while publishing new settings.
|
|
1649
1680
|
const models = await this.loadModels();
|
|
1681
|
+
if (!this.stopped)
|
|
1682
|
+
this.publishConfig(nativeId, models);
|
|
1683
|
+
}
|
|
1684
|
+
clearModels() {
|
|
1685
|
+
this.models = undefined;
|
|
1686
|
+
this.modelsLoadedAt = undefined;
|
|
1687
|
+
this.lastModels = [];
|
|
1688
|
+
}
|
|
1689
|
+
publishConfig(nativeId, models) {
|
|
1650
1690
|
const options = configOptions(this.settings.get(nativeId) ?? {}, this.overridesOf(nativeId), models);
|
|
1651
1691
|
if (options.length > 0 && this.isNews(`config:${nativeId}`, options))
|
|
1652
1692
|
this.host?.update(this.id, nativeId, { sessionUpdate: "ls_config", options });
|
|
@@ -1849,7 +1889,7 @@ export class CodexDriver {
|
|
|
1849
1889
|
});
|
|
1850
1890
|
}
|
|
1851
1891
|
onDown(reason) {
|
|
1852
|
-
this.
|
|
1892
|
+
this.clearModels();
|
|
1853
1893
|
this.skills.clear();
|
|
1854
1894
|
if (this.stopped)
|
|
1855
1895
|
return;
|