@rynx-ai/runtime 0.1.11-beta.29 → 0.1.11-beta.30
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.d.ts +3 -0
- package/dist/host.js +117 -33
- package/package.json +2 -2
package/dist/host.d.ts
CHANGED
|
@@ -196,6 +196,9 @@ export declare class LocalAgentHost implements CodexCapabilities {
|
|
|
196
196
|
* remember only a successful RPC. A supplied client is already initialized
|
|
197
197
|
* and remains owned by its caller (used by cold-resume preload). */
|
|
198
198
|
private applyLiveCollaborationMode;
|
|
199
|
+
/** Apply pending explicit model/effort settings and, when requested, one
|
|
200
|
+
* collaboration mode in a single native update. */
|
|
201
|
+
private applyLiveThreadSettings;
|
|
199
202
|
/**
|
|
200
203
|
* The command to run in a session's live terminal so it co-drives the codex
|
|
201
204
|
* app-server thread (Phase D). Returns `null` when live-terminal is off, the
|
package/dist/host.js
CHANGED
|
@@ -199,6 +199,7 @@ const CODEX_PLAN_IMPLEMENTATION_NO = "No, stay in Plan mode";
|
|
|
199
199
|
const CODEX_PLAN_IMPLEMENTATION_CODING_MESSAGE = "Implement the plan.";
|
|
200
200
|
const CODEX_PLAN_PROMPT_DISMISS_TIMEOUT_MS = 1_500;
|
|
201
201
|
const CODEX_PLAN_PROMPT_DISMISS_POLL_MS = 50;
|
|
202
|
+
const CODEX_SUBSCRIBE_FLUSH_RETRY_MS = 1_500;
|
|
202
203
|
const CODEX_PLAN_IMPLEMENTATION_CLEAR_CONTEXT_PREFIX = "A previous agent produced the plan below to accomplish the user's task. " +
|
|
203
204
|
"Implement the plan in a fresh context. Treat the plan as the source of " +
|
|
204
205
|
"user intent, re-read files as needed, and carry the work through " +
|
|
@@ -525,21 +526,49 @@ export class LocalAgentHost {
|
|
|
525
526
|
* remember only a successful RPC. A supplied client is already initialized
|
|
526
527
|
* and remains owned by its caller (used by cold-resume preload). */
|
|
527
528
|
async applyLiveCollaborationMode(live, threadId, mode, suppliedClient) {
|
|
528
|
-
|
|
529
|
-
|
|
529
|
+
await this.applyLiveThreadSettings(live, threadId, mode, suppliedClient);
|
|
530
|
+
}
|
|
531
|
+
/** Apply pending explicit model/effort settings and, when requested, one
|
|
532
|
+
* collaboration mode in a single native update. */
|
|
533
|
+
async applyLiveThreadSettings(live, threadId, mode, suppliedClient) {
|
|
530
534
|
const client = suppliedClient ?? this.injectionClientFactory(live.appServerUrl);
|
|
531
535
|
try {
|
|
532
536
|
if (!suppliedClient)
|
|
533
537
|
await client.ensureInitialized();
|
|
534
|
-
const
|
|
535
|
-
|
|
538
|
+
const desiredModel = live.model;
|
|
539
|
+
const desiredReasoningEffort = live.reasoningEffort;
|
|
540
|
+
const modelChanged = desiredModel !== live.appliedModel;
|
|
541
|
+
const effortChanged = desiredReasoningEffort !== live.appliedReasoningEffort;
|
|
542
|
+
const collaborationMode = mode && live.appliedCollaborationMode !== mode
|
|
543
|
+
? await resolveLiveCollaborationMode(client, live, mode)
|
|
544
|
+
: undefined;
|
|
545
|
+
const settings = {
|
|
536
546
|
threadId,
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
547
|
+
...(modelChanged ? { model: desiredModel || null } : {}),
|
|
548
|
+
...(effortChanged
|
|
549
|
+
? { effort: desiredReasoningEffort ?? null }
|
|
550
|
+
: {}),
|
|
551
|
+
...(collaborationMode ? { collaborationMode } : {}),
|
|
552
|
+
};
|
|
553
|
+
if (Object.keys(settings).length === 1)
|
|
554
|
+
return;
|
|
555
|
+
await client.threadSettingsUpdate(settings);
|
|
556
|
+
if (collaborationMode) {
|
|
557
|
+
if (!live.model)
|
|
558
|
+
live.model = collaborationMode.settings.model;
|
|
559
|
+
live.mayUseProviderDefaultModel = false;
|
|
560
|
+
live.appliedModel = collaborationMode.settings.model;
|
|
561
|
+
live.appliedReasoningEffort =
|
|
562
|
+
collaborationMode.settings.reasoning_effort ?? undefined;
|
|
563
|
+
live.appliedCollaborationMode = mode;
|
|
564
|
+
live.execution = { ...live.execution, collaborationMode: mode };
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
if (modelChanged)
|
|
568
|
+
live.appliedModel = desiredModel;
|
|
569
|
+
if (effortChanged)
|
|
570
|
+
live.appliedReasoningEffort = desiredReasoningEffort;
|
|
571
|
+
}
|
|
543
572
|
}
|
|
544
573
|
finally {
|
|
545
574
|
if (!suppliedClient)
|
|
@@ -689,6 +718,7 @@ export class LocalAgentHost {
|
|
|
689
718
|
this.stopLiveCodexSession(localThreadId);
|
|
690
719
|
}
|
|
691
720
|
const record = await this.sessionStore.get(localThreadId);
|
|
721
|
+
const coldResume = Boolean(record?.codexSessionId);
|
|
692
722
|
const retargetMirror = opts.retargetMirror;
|
|
693
723
|
const workspace = structuredClone(opts.workspace);
|
|
694
724
|
const execution = structuredClone(opts.execution);
|
|
@@ -755,7 +785,7 @@ export class LocalAgentHost {
|
|
|
755
785
|
// files or confusing `model/list.isDefault` with this Session's model.
|
|
756
786
|
let configModel;
|
|
757
787
|
let configReasoningEffort;
|
|
758
|
-
if (!execution.model || !execution.reasoningEffort) {
|
|
788
|
+
if (!coldResume && (!execution.model || !execution.reasoningEffort)) {
|
|
759
789
|
try {
|
|
760
790
|
const effective = await appServerOwner.configRead({
|
|
761
791
|
includeLayers: false,
|
|
@@ -792,7 +822,6 @@ export class LocalAgentHost {
|
|
|
792
822
|
// its observer starts in the background only after the replacement TUI has
|
|
793
823
|
// launched and is never part of the resume admission boundary.
|
|
794
824
|
const forwarderClient = this.forwarderClientFactory(appServerUrl);
|
|
795
|
-
const coldResume = Boolean(record?.codexSessionId);
|
|
796
825
|
if (!coldResume) {
|
|
797
826
|
try {
|
|
798
827
|
await forwarderClient.ensureInitialized();
|
|
@@ -803,8 +832,9 @@ export class LocalAgentHost {
|
|
|
803
832
|
return abandon();
|
|
804
833
|
}
|
|
805
834
|
}
|
|
806
|
-
const model = execution.model?.trim() || configModel || "";
|
|
807
|
-
const reasoningEffort = execution.reasoningEffort ??
|
|
835
|
+
const model = execution.model?.trim() || (!coldResume ? configModel : undefined) || "";
|
|
836
|
+
const reasoningEffort = execution.reasoningEffort ??
|
|
837
|
+
(!coldResume ? configReasoningEffort : undefined);
|
|
808
838
|
let markReady;
|
|
809
839
|
const ready = new Promise((resolve) => {
|
|
810
840
|
markReady = resolve;
|
|
@@ -829,8 +859,9 @@ export class LocalAgentHost {
|
|
|
829
859
|
approvalPolicy,
|
|
830
860
|
model,
|
|
831
861
|
reasoningEffort,
|
|
832
|
-
|
|
833
|
-
|
|
862
|
+
mayUseProviderDefaultModel: !coldResume && !model,
|
|
863
|
+
appliedModel: coldResume ? "" : model,
|
|
864
|
+
appliedReasoningEffort: coldResume ? undefined : reasoningEffort,
|
|
834
865
|
appliedCollaborationMode: undefined,
|
|
835
866
|
...(execution.instructions ? { instructions: execution.instructions } : {}),
|
|
836
867
|
threadId: record?.codexSessionId ?? null,
|
|
@@ -851,6 +882,7 @@ export class LocalAgentHost {
|
|
|
851
882
|
rotationPending: false,
|
|
852
883
|
stopped: false,
|
|
853
884
|
observerAvailable: !coldResume,
|
|
885
|
+
threadActive: false,
|
|
854
886
|
skillsCleanup: snapshotSkills.skillsCleanup,
|
|
855
887
|
canonicalInteractions: new Set(),
|
|
856
888
|
settledInteractions: new Set(),
|
|
@@ -1055,7 +1087,7 @@ export class LocalAgentHost {
|
|
|
1055
1087
|
const client = this.injectionClientFactory(live.appServerUrl);
|
|
1056
1088
|
try {
|
|
1057
1089
|
await client.ensureInitialized();
|
|
1058
|
-
const collaborationMode =
|
|
1090
|
+
const collaborationMode = await resolveLiveCollaborationMode(client, live, "default");
|
|
1059
1091
|
let threadId = prompt.threadId;
|
|
1060
1092
|
let text = CODEX_PLAN_IMPLEMENTATION_CODING_MESSAGE;
|
|
1061
1093
|
if (choice === CODEX_PLAN_IMPLEMENTATION_CLEAR_CONTEXT) {
|
|
@@ -1087,6 +1119,12 @@ export class LocalAgentHost {
|
|
|
1087
1119
|
approvalPolicy: live.approvalPolicy,
|
|
1088
1120
|
collaborationMode,
|
|
1089
1121
|
});
|
|
1122
|
+
if (!live.model)
|
|
1123
|
+
live.model = collaborationMode.settings.model;
|
|
1124
|
+
live.mayUseProviderDefaultModel = false;
|
|
1125
|
+
live.appliedModel = collaborationMode.settings.model;
|
|
1126
|
+
live.appliedReasoningEffort =
|
|
1127
|
+
collaborationMode.settings.reasoning_effort ?? undefined;
|
|
1090
1128
|
live.execution = { ...live.execution, collaborationMode: "default" };
|
|
1091
1129
|
live.appliedCollaborationMode = "default";
|
|
1092
1130
|
emitCurrent({
|
|
@@ -1313,7 +1351,10 @@ export class LocalAgentHost {
|
|
|
1313
1351
|
// A resumed TUI may rebroadcast `thread/started`; binding is idempotent.
|
|
1314
1352
|
shouldIgnoreThreadStarted: (threadId, forkedFromId) => this.shouldIgnoreManagedForkThreadStarted(live, threadId, forkedFromId),
|
|
1315
1353
|
onThreadStarted: (threadId, forkedFromId) => this.onLiveThreadStarted(live, localThreadId, threadId, forkedFromId),
|
|
1316
|
-
onThreadActive: () =>
|
|
1354
|
+
onThreadActive: () => {
|
|
1355
|
+
live.threadActive = true;
|
|
1356
|
+
live.releaseActive?.();
|
|
1357
|
+
},
|
|
1317
1358
|
onCollaborationModeChanged: (mode) => {
|
|
1318
1359
|
live.appliedCollaborationMode = mode;
|
|
1319
1360
|
live.execution = { ...live.execution, collaborationMode: mode };
|
|
@@ -1327,6 +1368,7 @@ export class LocalAgentHost {
|
|
|
1327
1368
|
if (reportedModel) {
|
|
1328
1369
|
live.model = reportedModel;
|
|
1329
1370
|
live.appliedModel = reportedModel;
|
|
1371
|
+
live.mayUseProviderDefaultModel = false;
|
|
1330
1372
|
}
|
|
1331
1373
|
if (reportedEffort !== undefined) {
|
|
1332
1374
|
live.reasoningEffort = reportedEffort ?? undefined;
|
|
@@ -1442,9 +1484,7 @@ export class LocalAgentHost {
|
|
|
1442
1484
|
excludeTurns: true,
|
|
1443
1485
|
});
|
|
1444
1486
|
adoptResumedThreadSettings(live, resumed);
|
|
1445
|
-
|
|
1446
|
-
await this.applyLiveCollaborationMode(live, resumed.threadId, execution.collaborationMode, preloadClient);
|
|
1447
|
-
}
|
|
1487
|
+
await this.applyLiveThreadSettings(live, resumed.threadId, execution.collaborationMode, preloadClient);
|
|
1448
1488
|
}
|
|
1449
1489
|
finally {
|
|
1450
1490
|
await preloadClient.stop().catch((error) => {
|
|
@@ -1466,6 +1506,7 @@ export class LocalAgentHost {
|
|
|
1466
1506
|
// not classified here because it does not prove the history is empty.
|
|
1467
1507
|
await this.sessionStore.delete(localThreadId);
|
|
1468
1508
|
live.threadId = null;
|
|
1509
|
+
live.mayUseProviderDefaultModel = !live.model;
|
|
1469
1510
|
try {
|
|
1470
1511
|
await forwarderClient.ensureInitialized();
|
|
1471
1512
|
}
|
|
@@ -1503,6 +1544,11 @@ export class LocalAgentHost {
|
|
|
1503
1544
|
* it, unblock injection, and kick off the resume-subscribe loop (once). */
|
|
1504
1545
|
onLiveThreadStarted(live, localThreadId, threadId, forkedFromId) {
|
|
1505
1546
|
const previousThreadId = live.threadId;
|
|
1547
|
+
if (previousThreadId !== threadId) {
|
|
1548
|
+
live.threadActive = false;
|
|
1549
|
+
if (!live.model)
|
|
1550
|
+
live.mayUseProviderDefaultModel = true;
|
|
1551
|
+
}
|
|
1506
1552
|
if (previousThreadId && previousThreadId !== threadId) {
|
|
1507
1553
|
live.threadId = threadId;
|
|
1508
1554
|
live.subscribing = true;
|
|
@@ -1654,13 +1700,20 @@ export class LocalAgentHost {
|
|
|
1654
1700
|
return false;
|
|
1655
1701
|
}
|
|
1656
1702
|
sawNotReady = true;
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1703
|
+
if (!live.threadActive) {
|
|
1704
|
+
// An idle fresh thread has no rollout until its first Turn. Wait only
|
|
1705
|
+
// for live activity instead of polling the app-server indefinitely.
|
|
1706
|
+
await new Promise((resolve) => {
|
|
1707
|
+
live.releaseActive = resolve;
|
|
1708
|
+
});
|
|
1709
|
+
live.releaseActive = undefined;
|
|
1710
|
+
}
|
|
1711
|
+
else {
|
|
1712
|
+
// Activity can precede rollout persistence by a short interval.
|
|
1713
|
+
await new Promise((resolve) => {
|
|
1714
|
+
setTimeout(resolve, CODEX_SUBSCRIBE_FLUSH_RETRY_MS);
|
|
1715
|
+
});
|
|
1716
|
+
}
|
|
1664
1717
|
}
|
|
1665
1718
|
}
|
|
1666
1719
|
return false;
|
|
@@ -1891,7 +1944,7 @@ export class LocalAgentHost {
|
|
|
1891
1944
|
const desiredCollaborationMode = options?.collaborationMode ?? live.execution.collaborationMode;
|
|
1892
1945
|
const collaborationMode = desiredCollaborationMode &&
|
|
1893
1946
|
desiredCollaborationMode !== live.appliedCollaborationMode
|
|
1894
|
-
?
|
|
1947
|
+
? await resolveLiveCollaborationMode(injectionClient, live, desiredCollaborationMode)
|
|
1895
1948
|
: undefined;
|
|
1896
1949
|
const settings = {
|
|
1897
1950
|
threadId,
|
|
@@ -1908,8 +1961,15 @@ export class LocalAgentHost {
|
|
|
1908
1961
|
// Record exactly what this RPC carried. A concurrent settings save may
|
|
1909
1962
|
// already have advanced the desired fields and must remain pending for
|
|
1910
1963
|
// the following new Turn.
|
|
1911
|
-
live.
|
|
1912
|
-
|
|
1964
|
+
if (collaborationMode && !live.model) {
|
|
1965
|
+
live.model = collaborationMode.settings.model;
|
|
1966
|
+
}
|
|
1967
|
+
if (collaborationMode)
|
|
1968
|
+
live.mayUseProviderDefaultModel = false;
|
|
1969
|
+
live.appliedModel = collaborationMode?.settings.model ?? desiredModel;
|
|
1970
|
+
live.appliedReasoningEffort = collaborationMode
|
|
1971
|
+
? collaborationMode.settings.reasoning_effort ?? undefined
|
|
1972
|
+
: desiredReasoningEffort;
|
|
1913
1973
|
if (desiredCollaborationMode) {
|
|
1914
1974
|
live.appliedCollaborationMode = desiredCollaborationMode;
|
|
1915
1975
|
live.execution = {
|
|
@@ -2944,6 +3004,7 @@ function raceReady(ready, timeoutMs, failed) {
|
|
|
2944
3004
|
function adoptResumedThreadSettings(live, settings) {
|
|
2945
3005
|
const model = settings.model?.trim();
|
|
2946
3006
|
if (model) {
|
|
3007
|
+
live.mayUseProviderDefaultModel = false;
|
|
2947
3008
|
live.appliedModel = model;
|
|
2948
3009
|
if (!live.execution.model)
|
|
2949
3010
|
live.model = model;
|
|
@@ -2955,9 +3016,32 @@ function adoptResumedThreadSettings(live, settings) {
|
|
|
2955
3016
|
}
|
|
2956
3017
|
}
|
|
2957
3018
|
}
|
|
3019
|
+
/** Resolve the model required by a full collaboration-mode snapshot. Only a
|
|
3020
|
+
* fresh thread with no explicit/config model may use the catalog default; a
|
|
3021
|
+
* resumed thread must report its own authoritative model. */
|
|
3022
|
+
async function resolveLiveCollaborationMode(client, live, mode) {
|
|
3023
|
+
let model = live.model.trim();
|
|
3024
|
+
if (!model && live.mayUseProviderDefaultModel) {
|
|
3025
|
+
let catalog;
|
|
3026
|
+
try {
|
|
3027
|
+
catalog = await client.modelList();
|
|
3028
|
+
}
|
|
3029
|
+
catch (error) {
|
|
3030
|
+
throw new CodexRuntimeError(`collaboration mode requires the Provider default model: ${error instanceof Error ? error.message : String(error)}`, 503, "collaboration_mode_model_unknown");
|
|
3031
|
+
}
|
|
3032
|
+
const defaults = [...new Set(catalog.data
|
|
3033
|
+
.filter((candidate) => candidate.isDefault === true)
|
|
3034
|
+
.map((candidate) => (candidate.model || candidate.id).trim())
|
|
3035
|
+
.filter(Boolean))];
|
|
3036
|
+
if (defaults.length !== 1) {
|
|
3037
|
+
throw new CodexRuntimeError(`collaboration mode requires exactly one Provider default model; Provider advertised ${defaults.length}`, 503, "collaboration_mode_model_unknown");
|
|
3038
|
+
}
|
|
3039
|
+
model = defaults[0];
|
|
3040
|
+
}
|
|
3041
|
+
return buildCollaborationMode(mode, model, live.reasoningEffort);
|
|
3042
|
+
}
|
|
2958
3043
|
/** Expand the public mode enum into the App Server's required settings
|
|
2959
|
-
* snapshot using the Session's tracked effective model.
|
|
2960
|
-
* catalog and its `isDefault` marker is not the current thread setting. */
|
|
3044
|
+
* snapshot using the Session's tracked effective model. */
|
|
2961
3045
|
function buildCollaborationMode(mode, desiredModel, desiredReasoningEffort) {
|
|
2962
3046
|
const model = desiredModel.trim();
|
|
2963
3047
|
if (!model) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/runtime",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.30",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"node-pty": "1.2.0-beta.15",
|
|
28
28
|
"smol-toml": "1.7.1",
|
|
29
29
|
"ws": "^8.21.0",
|
|
30
|
-
"@rynx-ai/core": "0.1.11-beta.
|
|
30
|
+
"@rynx-ai/core": "0.1.11-beta.30"
|
|
31
31
|
},
|
|
32
32
|
"devDependencies": {
|
|
33
33
|
"@types/ws": "^8.18.1"
|