@rynx-ai/server 0.1.11-beta.37 → 0.1.11-beta.39
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/control-web/assets/{abnfDiagram-VRR7QNED-CmU_MmlR.js → abnfDiagram-VRR7QNED-D_NL89dn.js} +1 -1
- package/dist/control-web/assets/architecture-TIHT7OUA-C9wU1KtW.js +1 -0
- package/dist/control-web/assets/{architectureDiagram-ZJ3FMSHR-OecV-i7M.js → architectureDiagram-ZJ3FMSHR-CV0rxVH6.js} +1 -1
- package/dist/control-web/assets/{blockDiagram-677ZJIJ3-DOxDUxjd.js → blockDiagram-677ZJIJ3-Cc7nrkZh.js} +1 -1
- package/dist/control-web/assets/{c4Diagram-LMCZKHZV-D557d6cD.js → c4Diagram-LMCZKHZV-BPRU9m-F.js} +1 -1
- package/dist/control-web/assets/channel-BFm2_j8K.js +1 -0
- package/dist/control-web/assets/{chunk-32BRIVSS-BfXRqSpF.js → chunk-32BRIVSS-Bbq3O54m.js} +1 -1
- package/dist/control-web/assets/{chunk-52WLFC77-BeKggk68.js → chunk-52WLFC77-sD4al-Ob.js} +1 -1
- package/dist/control-web/assets/{chunk-C7G6YPKG-D0W6xHti.js → chunk-C7G6YPKG-DqHaDS1O.js} +1 -1
- package/dist/control-web/assets/{chunk-EX3LRPZG-D-s3PHl_.js → chunk-EX3LRPZG-36GNQ5wp.js} +1 -1
- package/dist/control-web/assets/{chunk-HOUHSVGY-Cz-4R9wb.js → chunk-HOUHSVGY-DeZ63q1j.js} +1 -1
- package/dist/control-web/assets/{chunk-ICXQ74PX-Jh1cDG2d.js → chunk-ICXQ74PX-D2yF6lD_.js} +1 -1
- package/dist/control-web/assets/{chunk-MOJQB5TN-Bne3Czi6.js → chunk-MOJQB5TN-CdaKyBz5.js} +1 -1
- package/dist/control-web/assets/{chunk-OGEWGWER-B3ysgOD5.js → chunk-OGEWGWER-eOXC7kiH.js} +1 -1
- package/dist/control-web/assets/{chunk-PUDLZKDR-CcXYtnKN.js → chunk-PUDLZKDR-6w0LILL_.js} +1 -1
- package/dist/control-web/assets/{chunk-Q4XR5HBZ-puXEgeqv.js → chunk-Q4XR5HBZ-CXgD5TGL.js} +1 -1
- package/dist/control-web/assets/{chunk-V7JOEXUC-C3tvTxnz.js → chunk-V7JOEXUC-BfoZ78b6.js} +1 -1
- package/dist/control-web/assets/{chunk-VR4S4FIN-DW_38atK.js → chunk-VR4S4FIN-BW2gCEMQ.js} +1 -1
- package/dist/control-web/assets/{chunk-WYO6CB5R-Bbp0lWuA.js → chunk-WYO6CB5R-CHn7hulw.js} +3 -3
- package/dist/control-web/assets/{chunk-ZGVPDNZ5-EJHunJJc.js → chunk-ZGVPDNZ5-CmFP0-fr.js} +1 -1
- package/dist/control-web/assets/classDiagram-OUVF2IWQ-CUe_bETB.js +1 -0
- package/dist/control-web/assets/classDiagram-v2-EOCWNBFH-CUe_bETB.js +1 -0
- package/dist/control-web/assets/{cynefin-VYW2F7L2-BaT-TB_Y.js → cynefin-VYW2F7L2-NaLr7Qlq.js} +1 -1
- package/dist/control-web/assets/{cynefinDiagram-TSTJHNR4-sW0lbfzR.js → cynefinDiagram-TSTJHNR4-C90wpjAI.js} +1 -1
- package/dist/control-web/assets/{dagre-VKFMJZFB-DszFEQ50.js → dagre-VKFMJZFB-BxrPFWTb.js} +1 -1
- package/dist/control-web/assets/{diagram-FQU43EPY-BPueVs2y.js → diagram-FQU43EPY-VIQINsvz.js} +1 -1
- package/dist/control-web/assets/{diagram-G47NLZAW-BSgnrddi.js → diagram-G47NLZAW-DFeAfYXn.js} +1 -1
- package/dist/control-web/assets/{diagram-NH7WQ7WH-1WyXWZVF.js → diagram-NH7WQ7WH-ATzdppDd.js} +1 -1
- package/dist/control-web/assets/{diagram-OA4YK3LP--O72jADz.js → diagram-OA4YK3LP-DJZpWmbl.js} +1 -1
- package/dist/control-web/assets/{diagram-WEI45ONY-B2QpDXZ9.js → diagram-WEI45ONY-CqDHcW3g.js} +1 -1
- package/dist/control-web/assets/{dist-Dv-qw3vC.js → dist-Dx9YWgcW.js} +1 -1
- package/dist/control-web/assets/{ebnfDiagram-CCIWWBDH-DSs-ystO.js → ebnfDiagram-CCIWWBDH-DnP6dHND.js} +1 -1
- package/dist/control-web/assets/{erDiagram-Q63AITRT-Dd6hMu35.js → erDiagram-Q63AITRT-Bo8bFqrZ.js} +1 -1
- package/dist/control-web/assets/eventmodeling-45OFAUF4-DTN8wqsu.js +1 -0
- package/dist/control-web/assets/flowDiagram-23GEKE2U-BwjqRyvd.js +1 -0
- package/dist/control-web/assets/{ganttDiagram-NO4QXBWP-COHCKhqO.js → ganttDiagram-NO4QXBWP-kxQaBTzd.js} +1 -1
- package/dist/control-web/assets/{gitGraph-TEB2WS4Q-CysYOV0u.js → gitGraph-TEB2WS4Q-a646NnuJ.js} +1 -1
- package/dist/control-web/assets/{gitGraphDiagram-IHSO6WYX-RDxV8G1J.js → gitGraphDiagram-IHSO6WYX-BBe0q0At.js} +1 -1
- package/dist/control-web/assets/{highlighted-body-OFNGDK62-D0q5eseS.js → highlighted-body-OFNGDK62-DVCHy9oI.js} +1 -1
- package/dist/control-web/assets/{index-CfRLpoTC.js → index-D7URT6K_.js} +23 -23
- package/dist/control-web/assets/{info-DKCQHKI2-C8E_rmu3.js → info-DKCQHKI2-Cp_JrY-b.js} +1 -1
- package/dist/control-web/assets/{infoDiagram-FWYZ7A6U-BmH8cm18.js → infoDiagram-FWYZ7A6U-CAm-h4F_.js} +1 -1
- package/dist/control-web/assets/{ishikawaDiagram-FXEZZL3T-DR1Vhzx7.js → ishikawaDiagram-FXEZZL3T-O17pqcWr.js} +1 -1
- package/dist/control-web/assets/{journeyDiagram-5HDEW3XC-C7gr8G1Z.js → journeyDiagram-5HDEW3XC-DQ-JuSoR.js} +1 -1
- package/dist/control-web/assets/{kanban-definition-HUTT4EX6-Cg_3ELUy.js → kanban-definition-HUTT4EX6-Cgv3kPbm.js} +1 -1
- package/dist/control-web/assets/katex-CyHG4N6b.js +1 -0
- package/dist/control-web/assets/{line-Dt86r9Z9.js → line-DUsXzGJZ.js} +1 -1
- package/dist/control-web/assets/{markdown-streamdown-OYO-HVz6.js → markdown-streamdown-4N4AcNp5.js} +8 -8
- package/dist/control-web/assets/mermaid-GHXKKRXX-BElZGKGd.js +1 -0
- package/dist/control-web/assets/{mermaid-parser.core-pxV_1Fef.js → mermaid-parser.core-VMln12Kd.js} +3 -3
- package/dist/control-web/assets/{mindmap-definition-LN4V7U3C-CBevDwDF.js → mindmap-definition-LN4V7U3C-Bn0lH-UM.js} +1 -1
- package/dist/control-web/assets/{packet-7NZHBO7P-A9sKZzEL.js → packet-7NZHBO7P-Zw8iJ8lo.js} +1 -1
- package/dist/control-web/assets/{pegDiagram-2B236MQR-BTIvrl_V.js → pegDiagram-2B236MQR-CtF7vVs_.js} +1 -1
- package/dist/control-web/assets/{pie-RZYD4A2V-DUzb4QBE.js → pie-RZYD4A2V-su_3QGU2.js} +1 -1
- package/dist/control-web/assets/{pieDiagram-ENE6RG2P-CzmJJofh.js → pieDiagram-ENE6RG2P-BkMUBLE1.js} +1 -1
- package/dist/control-web/assets/{quadrantDiagram-ABIIQ3AL-D6bXvpAG.js → quadrantDiagram-ABIIQ3AL-ba-VaqMe.js} +1 -1
- package/dist/control-web/assets/{radar-I7S5WNFK-BV54nFux.js → radar-I7S5WNFK-Dat0rqem.js} +1 -1
- package/dist/control-web/assets/{railroad-3IZDKUUU-B2cY_UXv.js → railroad-3IZDKUUU-Dh2-s8r8.js} +1 -1
- package/dist/control-web/assets/railroad-abnf-AHOZXSZD-CNUwq0JR.js +1 -0
- package/dist/control-web/assets/railroad-ebnf-EBAXGLYW-RHr0duea.js +1 -0
- package/dist/control-web/assets/railroad-peg-LSFZ7HO6-CVBWS2eU.js +1 -0
- package/dist/control-web/assets/{railroadDiagram-RFXS5EU6-D_fo16vD.js → railroadDiagram-RFXS5EU6-BiJX3SY-.js} +1 -1
- package/dist/control-web/assets/{requirementDiagram-TGXJPOKE-D2yP7TUp.js → requirementDiagram-TGXJPOKE-CFfakCzs.js} +1 -1
- package/dist/control-web/assets/{sankeyDiagram-HTMAVEWB-By_qJ9BM.js → sankeyDiagram-HTMAVEWB-jgDi0God.js} +1 -1
- package/dist/control-web/assets/{sequenceDiagram-DBY2YBRQ-DgX1K1l4.js → sequenceDiagram-DBY2YBRQ-DBfyyb0N.js} +1 -1
- package/dist/control-web/assets/{stateDiagram-2N3HPSRC-CeUgjm3D.js → stateDiagram-2N3HPSRC-Dwb_ncVi.js} +1 -1
- package/dist/control-web/assets/stateDiagram-v2-6OUMAXLB-DI0opaA1.js +1 -0
- package/dist/control-web/assets/{swimlanes-5IMT3BWC-CTlZZmMW.js → swimlanes-5IMT3BWC-DW0LuiIV.js} +1 -1
- package/dist/control-web/assets/swimlanesDiagram-G3AALYLV-DDTVjcOR.js +8 -0
- package/dist/control-web/assets/{timeline-definition-FHXFAJF6-Cq3seh59.js → timeline-definition-FHXFAJF6-DeX4B_B8.js} +1 -1
- package/dist/control-web/assets/{treeView-QDETBFTQ-Cumz-G5q.js → treeView-QDETBFTQ-D1UXtICj.js} +1 -1
- package/dist/control-web/assets/{treemap-6X3UGDF4-Bq5v5pf6.js → treemap-6X3UGDF4-CrppzjZH.js} +1 -1
- package/dist/control-web/assets/{vennDiagram-L72KCM5P-Bx9PN1Pw.js → vennDiagram-L72KCM5P-BYpf-7VR.js} +1 -1
- package/dist/control-web/assets/{wardley-OPB4EBWU-DDRYn_rw.js → wardley-OPB4EBWU-B9rA0UsV.js} +1 -1
- package/dist/control-web/assets/{wardleyDiagram-EHGQE667-DOHp80dH.js → wardleyDiagram-EHGQE667-BdvAUa5F.js} +1 -1
- package/dist/control-web/assets/{xychartDiagram-FW5EYKEG-kaZ1Sn-e.js → xychartDiagram-FW5EYKEG-BaEV3pGm.js} +1 -1
- package/dist/control-web/index.html +1 -1
- package/dist/machine-session-service.d.ts +7 -1
- package/dist/machine-session-service.js +12 -1
- package/dist/remote-runtime-session-projection.js +6 -0
- package/dist/server.d.ts +17 -3
- package/dist/server.js +155 -32
- package/dist/session-pending-inputs.d.ts +2 -0
- package/dist/session-pending-inputs.js +6 -3
- package/dist/session-runtime-index.d.ts +1 -0
- package/dist/session-runtime-index.js +28 -2
- package/package.json +7 -7
- package/dist/control-web/assets/architecture-TIHT7OUA-BA6n-Dzl.js +0 -1
- package/dist/control-web/assets/channel-CvSP6WIQ.js +0 -1
- package/dist/control-web/assets/classDiagram-OUVF2IWQ-CbpSOtxx.js +0 -1
- package/dist/control-web/assets/classDiagram-v2-EOCWNBFH-CbpSOtxx.js +0 -1
- package/dist/control-web/assets/eventmodeling-45OFAUF4-B4JspsqG.js +0 -1
- package/dist/control-web/assets/flowDiagram-23GEKE2U-Ium-zrch.js +0 -1
- package/dist/control-web/assets/katex-BSYj5LXs.js +0 -1
- package/dist/control-web/assets/mermaid-GHXKKRXX-BybKptJt.js +0 -1
- package/dist/control-web/assets/railroad-abnf-AHOZXSZD-C6gyeMKO.js +0 -1
- package/dist/control-web/assets/railroad-ebnf-EBAXGLYW-CTnsShXg.js +0 -1
- package/dist/control-web/assets/railroad-peg-LSFZ7HO6-NgilCakK.js +0 -1
- package/dist/control-web/assets/stateDiagram-v2-6OUMAXLB-CsJT1Rvc.js +0 -1
- package/dist/control-web/assets/swimlanesDiagram-G3AALYLV-CzaTMmXS.js +0 -8
package/dist/server.js
CHANGED
|
@@ -5,6 +5,7 @@ import Router from "@koa/router";
|
|
|
5
5
|
import { loadConfig, listAgentSpecs, loadAgentSpec, resolveSessionExecution, resolveRuntimeModel, ConversationRuntime, InMemorySessionBus, persistSessionEvent, } from "@rynx-ai/core";
|
|
6
6
|
import { RunnerManager, FileCodexSessionStore, resolveCodexSessionStorePath, } from "@rynx-ai/runtime";
|
|
7
7
|
import { createControlRouter, } from "./control-api.js";
|
|
8
|
+
import { MachineSessionServiceFailure, MachineSessionServiceInputError, } from "./machine-session-service.js";
|
|
8
9
|
import { attachEmulatorTouchWs } from "./emulator-touch-ws.js";
|
|
9
10
|
import { attachTerminalWs } from "./terminal-ws.js";
|
|
10
11
|
import { attachBrowserSurfaceWs } from "./browser-surface-ws.js";
|
|
@@ -29,25 +30,74 @@ export { attachDirectRuntimeBrowserInspectServer, DirectRuntimeBrowserInspectHos
|
|
|
29
30
|
export { RemoteRuntimeDispatcher } from "./remote-runtime-dispatcher.js";
|
|
30
31
|
export { createRunnerSessionTerminalHost, SessionTerminalOpenError, SessionTerminalStreamError, } from "./session-terminal-host.js";
|
|
31
32
|
export { listRuntimeModels } from "@rynx-ai/runtime";
|
|
32
|
-
/**
|
|
33
|
+
/** Bound one mirror write at ten seconds. After that uncertainty boundary,
|
|
34
|
+
* later records may start instead
|
|
35
|
+
* of waiting forever behind a persistence call whose result is unknown. */
|
|
36
|
+
const SESSION_MIRROR_STALL_TIMEOUT_MS = 10_000;
|
|
37
|
+
class SessionMirrorAmbiguousError extends Error {
|
|
38
|
+
abandonToken;
|
|
39
|
+
mirrorClassification = "ambiguous";
|
|
40
|
+
constructor(sessionId, abandonToken) {
|
|
41
|
+
super(`Session mirror persistence did not settle before its response deadline: ${sessionId}`);
|
|
42
|
+
this.abandonToken = abandonToken;
|
|
43
|
+
this.name = "SessionMirrorAmbiguousError";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function preparedMirrorPersistence(persistence) {
|
|
47
|
+
if (typeof persistence === "object" &&
|
|
48
|
+
persistence !== null &&
|
|
49
|
+
"promise" in persistence)
|
|
50
|
+
return persistence;
|
|
51
|
+
return { promise: persistence };
|
|
52
|
+
}
|
|
53
|
+
/** Preserve one session's mirror order without serializing unrelated sessions.
|
|
54
|
+
* A timed-out operation is not cancelled: like an HTTP read timeout, it may
|
|
55
|
+
* still commit later. Its caller receives `ambiguous` and must not retry. */
|
|
33
56
|
export class SessionMirrorQueue {
|
|
34
57
|
persist;
|
|
58
|
+
stallTimeoutMs;
|
|
35
59
|
tails = new Map();
|
|
36
|
-
constructor(persist) {
|
|
60
|
+
constructor(persist, stallTimeoutMs = SESSION_MIRROR_STALL_TIMEOUT_MS) {
|
|
37
61
|
this.persist = persist;
|
|
62
|
+
this.stallTimeoutMs = stallTimeoutMs;
|
|
38
63
|
}
|
|
39
64
|
enqueue(sessionId, event) {
|
|
40
65
|
const previous = this.tails.get(sessionId) ?? Promise.resolve();
|
|
41
|
-
const
|
|
66
|
+
const bounded = previous
|
|
42
67
|
.catch(() => undefined)
|
|
43
|
-
.then(() =>
|
|
44
|
-
|
|
68
|
+
.then(() => {
|
|
69
|
+
// Prepare only when this record reaches the head of its Session lane.
|
|
70
|
+
// Starting either persistence or its deadline while an older record is
|
|
71
|
+
// still ahead would shorten queued records' attempt windows and allow a
|
|
72
|
+
// burst of them to time out concurrently.
|
|
73
|
+
const prepared = preparedMirrorPersistence(this.persist(sessionId, event));
|
|
74
|
+
let timer;
|
|
75
|
+
return new Promise((resolve, reject) => {
|
|
76
|
+
timer = setTimeout(() => {
|
|
77
|
+
// A user echo claims one exact optimistic pending input while the
|
|
78
|
+
// write starts. Retire it synchronously before rejecting this tail:
|
|
79
|
+
// the next echo must never peek the same content or attachments.
|
|
80
|
+
prepared.onAmbiguous?.();
|
|
81
|
+
reject(new SessionMirrorAmbiguousError(sessionId, prepared.abandonToken));
|
|
82
|
+
}, this.stallTimeoutMs);
|
|
83
|
+
timer.unref?.();
|
|
84
|
+
void prepared.promise.then(resolve, reject);
|
|
85
|
+
}).finally(() => {
|
|
86
|
+
if (timer)
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
// The bounded result, not the potentially immortal persistence promise,
|
|
91
|
+
// gates the next record. `operation` remains observed by `bounded`, so a
|
|
92
|
+
// late rejection cannot become an unhandled promise rejection.
|
|
93
|
+
const tail = bounded.catch(() => undefined);
|
|
94
|
+
this.tails.set(sessionId, tail);
|
|
45
95
|
const cleanup = () => {
|
|
46
|
-
if (this.tails.get(sessionId) ===
|
|
96
|
+
if (this.tails.get(sessionId) === tail)
|
|
47
97
|
this.tails.delete(sessionId);
|
|
48
98
|
};
|
|
49
|
-
void
|
|
50
|
-
return
|
|
99
|
+
void tail.then(cleanup, cleanup);
|
|
100
|
+
return bounded;
|
|
51
101
|
}
|
|
52
102
|
}
|
|
53
103
|
/**
|
|
@@ -68,31 +118,57 @@ export function createSessionRuntimeServices(input) {
|
|
|
68
118
|
});
|
|
69
119
|
const sessionBus = new InMemorySessionBus();
|
|
70
120
|
const sessionRuntimeIndex = new SessionRuntimeIndex();
|
|
71
|
-
const sessionMirrorQueue = new SessionMirrorQueue(
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
121
|
+
const sessionMirrorQueue = new SessionMirrorQueue((sessionId, event) => {
|
|
122
|
+
// Claim the exact pending projection synchronously when this record reaches
|
|
123
|
+
// the head of its Session lane. Its id remains stable even if persistence
|
|
124
|
+
// later times out or fails after the result becomes ambiguous.
|
|
125
|
+
const pendingResolved = resolvePendingInputEvent(sessionId, event, input.pendingInputs);
|
|
126
|
+
const pendingId = pendingResolved.pendingId;
|
|
127
|
+
const promise = (async () => {
|
|
128
|
+
const finalized = await finalizeGeneratedImageEvent(sessionId, pendingResolved.event, input);
|
|
129
|
+
try {
|
|
130
|
+
await persistSessionEvent(sessionId, finalized, {
|
|
131
|
+
sessionLog: input.sessionLog,
|
|
132
|
+
sessionBus,
|
|
133
|
+
strictPersistence: true,
|
|
134
|
+
...(pendingId
|
|
135
|
+
? {
|
|
136
|
+
onInputPersisted: async (persistedEvent) => {
|
|
137
|
+
if (persistedEvent.clearedPendingId !== pendingId)
|
|
138
|
+
return;
|
|
139
|
+
input.pendingInputs?.resolve(sessionId, pendingId);
|
|
140
|
+
if (!input.onPendingInputPersisted || !pendingResolved.clientMessageId)
|
|
141
|
+
return;
|
|
142
|
+
await input.onPendingInputPersisted({
|
|
143
|
+
sessionId,
|
|
144
|
+
pendingId: persistedEvent.clearedPendingId,
|
|
145
|
+
clientMessageId: pendingResolved.clientMessageId,
|
|
146
|
+
responseId: persistedEvent.item.responseId,
|
|
147
|
+
messageItemId: persistedEvent.item.id,
|
|
148
|
+
});
|
|
149
|
+
},
|
|
150
|
+
}
|
|
151
|
+
: {}),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (pendingId) {
|
|
156
|
+
throw new PendingInputMirrorPersistenceError(error, pendingId);
|
|
157
|
+
}
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
sessionRuntimeIndex.observe(sessionId, finalized);
|
|
161
|
+
})();
|
|
162
|
+
return {
|
|
163
|
+
promise,
|
|
164
|
+
...(pendingId
|
|
80
165
|
? {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return;
|
|
84
|
-
await input.onPendingInputPersisted({
|
|
85
|
-
sessionId,
|
|
86
|
-
pendingId: persistedEvent.clearedPendingId,
|
|
87
|
-
clientMessageId: pendingFinalized.clientMessageId,
|
|
88
|
-
responseId: persistedEvent.item.responseId,
|
|
89
|
-
messageItemId: persistedEvent.item.id,
|
|
90
|
-
});
|
|
91
|
-
},
|
|
166
|
+
abandonToken: pendingId,
|
|
167
|
+
onAmbiguous: () => input.pendingInputs?.resolve(sessionId, pendingId),
|
|
92
168
|
}
|
|
93
169
|
: {}),
|
|
94
|
-
}
|
|
95
|
-
});
|
|
170
|
+
};
|
|
171
|
+
}, input.mirrorStallTimeoutMs);
|
|
96
172
|
const mirrorSessionEvent = (sessionId, event) => {
|
|
97
173
|
return sessionMirrorQueue.enqueue(sessionId, event);
|
|
98
174
|
};
|
|
@@ -104,8 +180,15 @@ export function createSessionRuntimeServices(input) {
|
|
|
104
180
|
runnerManager.onMirror((sessionId, event) => {
|
|
105
181
|
return mirrorSessionEvent(sessionId, event).catch((error) => {
|
|
106
182
|
input.onMirrorError?.(error, sessionId);
|
|
183
|
+
throw error;
|
|
107
184
|
});
|
|
108
185
|
});
|
|
186
|
+
runnerManager.onMirrorAbandon((sessionId, pendingId) => {
|
|
187
|
+
input.pendingInputs?.resolve(sessionId, pendingId);
|
|
188
|
+
});
|
|
189
|
+
runnerManager.onMirrorSupersede((sessionId) => {
|
|
190
|
+
input.pendingInputs?.deleteSession(sessionId);
|
|
191
|
+
});
|
|
109
192
|
return {
|
|
110
193
|
sessionStore,
|
|
111
194
|
runnerManager,
|
|
@@ -115,6 +198,20 @@ export function createSessionRuntimeServices(input) {
|
|
|
115
198
|
publishSessionEvent: mirrorSessionEvent,
|
|
116
199
|
};
|
|
117
200
|
}
|
|
201
|
+
class PendingInputMirrorPersistenceError extends Error {
|
|
202
|
+
abandonToken;
|
|
203
|
+
statusCode;
|
|
204
|
+
constructor(error, abandonToken) {
|
|
205
|
+
super(error instanceof Error ? error.message : String(error), { cause: error });
|
|
206
|
+
this.abandonToken = abandonToken;
|
|
207
|
+
this.name = "PendingInputMirrorPersistenceError";
|
|
208
|
+
if (typeof error === "object" &&
|
|
209
|
+
error !== null &&
|
|
210
|
+
typeof error.statusCode === "number") {
|
|
211
|
+
this.statusCode = error.statusCode;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
118
215
|
/** Drain the oldest pending web input when the Provider transcript produces a
|
|
119
216
|
* real user record. The transcript is the only durable writer; the returned id
|
|
120
217
|
* lets clients replace the exact temporary bubble. */
|
|
@@ -122,10 +219,11 @@ function resolvePendingInputEvent(sessionId, event, pendingInputs) {
|
|
|
122
219
|
if (event.type !== "session.input.consumed" ||
|
|
123
220
|
event.item.type !== "message" ||
|
|
124
221
|
event.item.data.role !== "user" ||
|
|
125
|
-
event.item.data.isMeta
|
|
222
|
+
event.item.data.isMeta ||
|
|
223
|
+
event.item.parentToolCallId !== undefined) {
|
|
126
224
|
return { event };
|
|
127
225
|
}
|
|
128
|
-
const pending = pendingInputs?.
|
|
226
|
+
const pending = pendingInputs?.peekOldest(sessionId);
|
|
129
227
|
if (!pending)
|
|
130
228
|
return { event };
|
|
131
229
|
const fileParts = pending.content.filter((part) => part.type === "input_image" || part.type === "input_file");
|
|
@@ -138,6 +236,7 @@ function resolvePendingInputEvent(sessionId, event, pendingInputs) {
|
|
|
138
236
|
? [...fileParts, ...event.item.data.content]
|
|
139
237
|
: event.item.data.content;
|
|
140
238
|
return {
|
|
239
|
+
pendingId: pending.pendingId,
|
|
141
240
|
clientMessageId: pending.clientMessageId,
|
|
142
241
|
event: {
|
|
143
242
|
...event,
|
|
@@ -199,6 +298,14 @@ async function finalizeGeneratedImageEvent(sessionId, event, input) {
|
|
|
199
298
|
}
|
|
200
299
|
catch (error) {
|
|
201
300
|
input.onMirrorError?.(error, sessionId);
|
|
301
|
+
// The source bytes are part of an ordinary durable delivery.
|
|
302
|
+
// Only deterministic validation/conflict failures may discard their
|
|
303
|
+
// preview; infrastructure and explicitly retryable resource failures must
|
|
304
|
+
// NACK so the child retries the exact image commit.
|
|
305
|
+
if (!(error instanceof MachineSessionServiceFailure) ||
|
|
306
|
+
error.retryable) {
|
|
307
|
+
throw error;
|
|
308
|
+
}
|
|
202
309
|
return {
|
|
203
310
|
...event,
|
|
204
311
|
item: {
|
|
@@ -421,6 +528,22 @@ export async function startServer({ config = loadConfig(), control, sessionLog,
|
|
|
421
528
|
sourceSessionId: r.from,
|
|
422
529
|
targetSessionId: r.to,
|
|
423
530
|
kind: r.kind,
|
|
531
|
+
}).catch((error) => {
|
|
532
|
+
if (error instanceof MachineSessionServiceInputError) {
|
|
533
|
+
throw Object.assign(error, { statusCode: 400 });
|
|
534
|
+
}
|
|
535
|
+
if (error instanceof MachineSessionServiceFailure) {
|
|
536
|
+
// A mismatched pre-existing target is a deterministic payload conflict,
|
|
537
|
+
// not an HTTP-style concurrent 409. Surface it as permanent so the
|
|
538
|
+
// three-attempt permanent-error budget can stop the rotation lane.
|
|
539
|
+
const statusCode = error.code === "outcome_unknown"
|
|
540
|
+
? 503
|
|
541
|
+
: error.code === "not_found"
|
|
542
|
+
? 404
|
|
543
|
+
: 422;
|
|
544
|
+
throw Object.assign(error, { statusCode });
|
|
545
|
+
}
|
|
546
|
+
throw error;
|
|
424
547
|
});
|
|
425
548
|
});
|
|
426
549
|
if (localMachineSessions) {
|
|
@@ -13,6 +13,7 @@ export interface MachineSessionDrainedInput extends MachineSessionPendingInput {
|
|
|
13
13
|
export interface MachineSessionPendingInputPort {
|
|
14
14
|
record(sessionId: string, input: MachineSessionPendingInputRecord): string;
|
|
15
15
|
resolve(sessionId: string, pendingId: string): void;
|
|
16
|
+
peekOldest(sessionId: string): MachineSessionDrainedInput | undefined;
|
|
16
17
|
resolveOldest(sessionId: string): MachineSessionDrainedInput | undefined;
|
|
17
18
|
findByClientMessageId(sessionId: string, clientMessageId: string): MachineSessionPendingInput | undefined;
|
|
18
19
|
snapshotFor(sessionId: string): MachineSessionPendingInput[];
|
|
@@ -33,6 +34,7 @@ export declare class SessionPendingInputIndex implements MachineSessionPendingIn
|
|
|
33
34
|
record(sessionId: string, input: MachineSessionPendingInputRecord): string;
|
|
34
35
|
resolve(sessionId: string, pendingId: string): void;
|
|
35
36
|
resolveOldest(sessionId: string): MachineSessionDrainedInput | undefined;
|
|
37
|
+
peekOldest(sessionId: string): MachineSessionDrainedInput | undefined;
|
|
36
38
|
findByClientMessageId(sessionId: string, clientMessageId: string): MachineSessionPendingInput | undefined;
|
|
37
39
|
snapshotFor(sessionId: string): MachineSessionPendingInput[];
|
|
38
40
|
deleteSession(sessionId: string): void;
|
|
@@ -37,15 +37,18 @@ export class SessionPendingInputIndex {
|
|
|
37
37
|
this.entries.delete(sessionId);
|
|
38
38
|
}
|
|
39
39
|
resolveOldest(sessionId) {
|
|
40
|
+
const input = this.peekOldest(sessionId);
|
|
41
|
+
if (input)
|
|
42
|
+
this.resolve(sessionId, input.pendingId);
|
|
43
|
+
return input;
|
|
44
|
+
}
|
|
45
|
+
peekOldest(sessionId) {
|
|
40
46
|
this.evictStale(sessionId);
|
|
41
47
|
const pending = this.entries.get(sessionId);
|
|
42
48
|
const pendingId = pending?.keys().next().value;
|
|
43
49
|
if (!pending || !pendingId)
|
|
44
50
|
return undefined;
|
|
45
51
|
const input = pending.get(pendingId);
|
|
46
|
-
pending.delete(pendingId);
|
|
47
|
-
if (pending.size === 0)
|
|
48
|
-
this.entries.delete(sessionId);
|
|
49
52
|
return input ? cloneDrainedInput(input) : undefined;
|
|
50
53
|
}
|
|
51
54
|
findByClientMessageId(sessionId, clientMessageId) {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
const MAX_TERMINAL_RESPONSE_IDS = 2_000;
|
|
1
2
|
/**
|
|
2
3
|
* Process-local index of live Session state. Durable transcript items explain
|
|
3
4
|
* history; this index says which historical requests still have a real runtime
|
|
@@ -10,18 +11,22 @@ export class SessionRuntimeIndex {
|
|
|
10
11
|
const state = this.state(sessionId);
|
|
11
12
|
switch (event.type) {
|
|
12
13
|
case "response.created":
|
|
14
|
+
if (state.terminalResponseIds.has(event.responseId))
|
|
15
|
+
return;
|
|
13
16
|
state.activeResponseIds.add(event.responseId);
|
|
14
17
|
state.status = "running";
|
|
15
18
|
state.statusKind = undefined;
|
|
16
19
|
state.backgroundTaskCount = undefined;
|
|
17
20
|
return;
|
|
18
21
|
case "response.completed":
|
|
22
|
+
this.markResponseTerminal(state, event.responseId);
|
|
19
23
|
state.activeResponseIds.delete(event.responseId);
|
|
20
24
|
this.removeResponseInteractions(state, event.responseId);
|
|
21
25
|
state.status = this.statusAfterResponseTerminal(state);
|
|
22
26
|
state.statusKind = undefined;
|
|
23
27
|
return;
|
|
24
28
|
case "response.failed":
|
|
29
|
+
this.markResponseTerminal(state, event.responseId);
|
|
25
30
|
state.activeResponseIds.delete(event.responseId);
|
|
26
31
|
this.removeResponseInteractions(state, event.responseId);
|
|
27
32
|
// Response failure is Turn-local. It must not poison a reusable Session.
|
|
@@ -29,6 +34,7 @@ export class SessionRuntimeIndex {
|
|
|
29
34
|
state.statusKind = undefined;
|
|
30
35
|
return;
|
|
31
36
|
case "session.interrupted":
|
|
37
|
+
this.markResponseTerminal(state, event.responseId);
|
|
32
38
|
state.activeResponseIds.delete(event.responseId);
|
|
33
39
|
this.removeResponseInteractions(state, event.responseId);
|
|
34
40
|
state.status = this.statusAfterResponseTerminal(state);
|
|
@@ -44,6 +50,8 @@ export class SessionRuntimeIndex {
|
|
|
44
50
|
state.backgroundTaskCount = undefined;
|
|
45
51
|
}
|
|
46
52
|
if (event.status === "running") {
|
|
53
|
+
if (event.responseId && state.terminalResponseIds.has(event.responseId))
|
|
54
|
+
return;
|
|
47
55
|
if (event.responseId)
|
|
48
56
|
state.activeResponseIds.add(event.responseId);
|
|
49
57
|
state.status = "running";
|
|
@@ -58,7 +66,7 @@ export class SessionRuntimeIndex {
|
|
|
58
66
|
state.statusKind = undefined;
|
|
59
67
|
return;
|
|
60
68
|
}
|
|
61
|
-
this.retireStatusResponses(state);
|
|
69
|
+
this.retireStatusResponses(state, event.responseId);
|
|
62
70
|
if (event.status === "failed") {
|
|
63
71
|
state.status = "failed";
|
|
64
72
|
}
|
|
@@ -72,6 +80,8 @@ export class SessionRuntimeIndex {
|
|
|
72
80
|
return;
|
|
73
81
|
}
|
|
74
82
|
case "session.interaction.requested":
|
|
83
|
+
if (state.terminalResponseIds.has(event.responseId))
|
|
84
|
+
return;
|
|
75
85
|
state.pendingInteractions.set(event.interaction.interactionId, {
|
|
76
86
|
responseId: event.responseId,
|
|
77
87
|
interaction: event.interaction,
|
|
@@ -132,6 +142,7 @@ export class SessionRuntimeIndex {
|
|
|
132
142
|
state = {
|
|
133
143
|
status: "idle",
|
|
134
144
|
activeResponseIds: new Set(),
|
|
145
|
+
terminalResponseIds: new Set(),
|
|
135
146
|
pendingInteractions: new Map(),
|
|
136
147
|
};
|
|
137
148
|
this.sessions.set(sessionId, state);
|
|
@@ -152,13 +163,28 @@ export class SessionRuntimeIndex {
|
|
|
152
163
|
return "running";
|
|
153
164
|
return state.status === "failed" ? "failed" : "idle";
|
|
154
165
|
}
|
|
155
|
-
retireStatusResponses(state) {
|
|
166
|
+
retireStatusResponses(state, responseId) {
|
|
156
167
|
// session.status is Session-wide. Match reference implementation's
|
|
157
168
|
// _session_active_response_cache: every idle/failed edge closes the one
|
|
158
169
|
// in-flight native response projection, even when the edge happens to be
|
|
159
170
|
// stamped with that response id. A late transcript event may still carry
|
|
160
171
|
// the old id for grouping, but it cannot keep activity alive.
|
|
172
|
+
for (const activeResponseId of state.activeResponseIds) {
|
|
173
|
+
this.markResponseTerminal(state, activeResponseId);
|
|
174
|
+
}
|
|
175
|
+
if (responseId)
|
|
176
|
+
this.markResponseTerminal(state, responseId);
|
|
161
177
|
state.activeResponseIds.clear();
|
|
162
178
|
state.pendingInteractions.clear();
|
|
163
179
|
}
|
|
180
|
+
markResponseTerminal(state, responseId) {
|
|
181
|
+
state.terminalResponseIds.delete(responseId);
|
|
182
|
+
state.terminalResponseIds.add(responseId);
|
|
183
|
+
while (state.terminalResponseIds.size > MAX_TERMINAL_RESPONSE_IDS) {
|
|
184
|
+
const oldest = state.terminalResponseIds.values().next().value;
|
|
185
|
+
if (oldest === undefined)
|
|
186
|
+
break;
|
|
187
|
+
state.terminalResponseIds.delete(oldest);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
164
190
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/server",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.39",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"@koa/router": "^15.4.0",
|
|
28
28
|
"koa": "^3.2.0",
|
|
29
29
|
"ws": "^8.21.0",
|
|
30
|
-
"@rynx-ai/
|
|
31
|
-
"@rynx-ai/
|
|
32
|
-
"@rynx-ai/protocol": "0.1.11-beta.
|
|
33
|
-
"@rynx-ai/remote-runtime-e2ee": "0.1.11-beta.
|
|
34
|
-
"@rynx-ai/runtime": "0.1.11-beta.
|
|
30
|
+
"@rynx-ai/core": "0.1.11-beta.39",
|
|
31
|
+
"@rynx-ai/plugin-sdk": "0.1.11-beta.39",
|
|
32
|
+
"@rynx-ai/protocol": "0.1.11-beta.39",
|
|
33
|
+
"@rynx-ai/remote-runtime-e2ee": "0.1.11-beta.39",
|
|
34
|
+
"@rynx-ai/runtime": "0.1.11-beta.39"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/ws": "^8.18.1",
|
|
38
|
-
"@rynx-ai/control-web": "0.1.11-beta.
|
|
38
|
+
"@rynx-ai/control-web": "0.1.11-beta.39"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "rm -rf dist && tsc -p tsconfig.json && mkdir -p dist/control-web && cp -R ../control-web/dist/. dist/control-web/",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunk-KEIR6QF5-BICK3FdT.js";import{M as e}from"./mermaid-parser.core-pxV_1Fef.js";export{e as createArchitectureServices};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{at as e,ot as t}from"./chunk-WYO6CB5R-Bbp0lWuA.js";var n=(n,r)=>t.lang.round(e.parse(n)[r]);export{n as t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./src-B6xuSHsQ.js";import"./chunk-WYO6CB5R-Bbp0lWuA.js";import"./chunk-ICXQ74PX-Jh1cDG2d.js";import"./chunk-HOUHSVGY-Cz-4R9wb.js";import"./chunk-Q4XR5HBZ-puXEgeqv.js";import"./chunk-7BUUIJ7U-Bb538aSH.js";import"./chunk-OGEWGWER-B3ysgOD5.js";import"./chunk-32BRIVSS-BfXRqSpF.js";import"./chunk-XXDRQBXY-DqAYeljN.js";import"./chunk-VR4S4FIN-DW_38atK.js";import"./chunk-C7G6YPKG-D0W6xHti.js";import"./chunk-ZGVPDNZ5-EJHunJJc.js";import"./chunk-52WLFC77-BeKggk68.js";import{i as t,n,r,t as i}from"./chunk-V7JOEXUC-C3tvTxnz.js";import"./markdown-streamdown-OYO-HVz6.js";var a={parser:n,get db(){return new i},renderer:r,styles:t,init:e(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./src-B6xuSHsQ.js";import"./chunk-WYO6CB5R-Bbp0lWuA.js";import"./chunk-ICXQ74PX-Jh1cDG2d.js";import"./chunk-HOUHSVGY-Cz-4R9wb.js";import"./chunk-Q4XR5HBZ-puXEgeqv.js";import"./chunk-7BUUIJ7U-Bb538aSH.js";import"./chunk-OGEWGWER-B3ysgOD5.js";import"./chunk-32BRIVSS-BfXRqSpF.js";import"./chunk-XXDRQBXY-DqAYeljN.js";import"./chunk-VR4S4FIN-DW_38atK.js";import"./chunk-C7G6YPKG-D0W6xHti.js";import"./chunk-ZGVPDNZ5-EJHunJJc.js";import"./chunk-52WLFC77-BeKggk68.js";import{i as t,n,r,t as i}from"./chunk-V7JOEXUC-C3tvTxnz.js";import"./markdown-streamdown-OYO-HVz6.js";var a={parser:n,get db(){return new i},renderer:r,styles:t,init:e(e=>{e.class||={},e.class.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunk-KEIR6QF5-BICK3FdT.js";import{O as e}from"./mermaid-parser.core-pxV_1Fef.js";export{e as createEventModelingServices};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./src-B6xuSHsQ.js";import"./chunk-WYO6CB5R-Bbp0lWuA.js";import"./chunk-ICXQ74PX-Jh1cDG2d.js";import"./chunk-HOUHSVGY-Cz-4R9wb.js";import"./chunk-Q4XR5HBZ-puXEgeqv.js";import"./chunk-7BUUIJ7U-Bb538aSH.js";import"./chunk-OGEWGWER-B3ysgOD5.js";import"./chunk-32BRIVSS-BfXRqSpF.js";import"./chunk-XXDRQBXY-DqAYeljN.js";import"./chunk-VR4S4FIN-DW_38atK.js";import"./chunk-C7G6YPKG-D0W6xHti.js";import"./chunk-ZGVPDNZ5-EJHunJJc.js";import"./chunk-52WLFC77-BeKggk68.js";import{n as e}from"./chunk-PUDLZKDR-CcXYtnKN.js";import"./markdown-streamdown-OYO-HVz6.js";export{e as diagram};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as e}from"./markdown-streamdown-OYO-HVz6.js";export{e as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e}from"./markdown-streamdown-OYO-HVz6.js";export{e as Mermaid};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunk-KEIR6QF5-BICK3FdT.js";import{m as e}from"./mermaid-parser.core-pxV_1Fef.js";export{e as createRailroadAbnfServices};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunk-KEIR6QF5-BICK3FdT.js";import{f as e}from"./mermaid-parser.core-pxV_1Fef.js";export{e as createRailroadEbnfServices};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import"./chunk-KEIR6QF5-BICK3FdT.js";import{u as e}from"./mermaid-parser.core-pxV_1Fef.js";export{e as createRailroadPegServices};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./src-B6xuSHsQ.js";import"./chunk-WYO6CB5R-Bbp0lWuA.js";import"./chunk-ICXQ74PX-Jh1cDG2d.js";import"./chunk-HOUHSVGY-Cz-4R9wb.js";import"./chunk-Q4XR5HBZ-puXEgeqv.js";import"./chunk-7BUUIJ7U-Bb538aSH.js";import"./chunk-OGEWGWER-B3ysgOD5.js";import"./chunk-32BRIVSS-BfXRqSpF.js";import"./chunk-XXDRQBXY-DqAYeljN.js";import"./chunk-VR4S4FIN-DW_38atK.js";import"./chunk-C7G6YPKG-D0W6xHti.js";import"./chunk-ZGVPDNZ5-EJHunJJc.js";import"./chunk-52WLFC77-BeKggk68.js";import{i as t,n,r,t as i}from"./chunk-EX3LRPZG-D-s3PHl_.js";import"./markdown-streamdown-OYO-HVz6.js";var a={parser:n,get db(){return new i(2)},renderer:r,styles:t,init:e(e=>{e.state||={},e.state.arrowMarkerAbsolute=e.arrowMarkerAbsolute},`init`)};export{a as diagram};
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./chunk-Y2CYZVJY-DsF7k-Jl.js";import"./src-B6xuSHsQ.js";import"./chunk-WYO6CB5R-Bbp0lWuA.js";import"./chunk-ICXQ74PX-Jh1cDG2d.js";import"./chunk-HOUHSVGY-Cz-4R9wb.js";import"./chunk-Q4XR5HBZ-puXEgeqv.js";import"./chunk-7BUUIJ7U-Bb538aSH.js";import"./chunk-OGEWGWER-B3ysgOD5.js";import"./chunk-32BRIVSS-BfXRqSpF.js";import"./chunk-XXDRQBXY-DqAYeljN.js";import"./chunk-VR4S4FIN-DW_38atK.js";import"./chunk-C7G6YPKG-D0W6xHti.js";import"./chunk-ZGVPDNZ5-EJHunJJc.js";import"./chunk-52WLFC77-BeKggk68.js";import{r as t,t as n}from"./chunk-PUDLZKDR-CcXYtnKN.js";import"./markdown-streamdown-OYO-HVz6.js";var r=n({defaultLayout:`swimlane`,styles:e(e=>`${t(e)}
|
|
2
|
-
.swimlane.cluster rect {
|
|
3
|
-
stroke: ${e.clusterBorder} !important;
|
|
4
|
-
}
|
|
5
|
-
[data-look="neo"].cluster rect {
|
|
6
|
-
filter: none;
|
|
7
|
-
}
|
|
8
|
-
`,`getStyles`)});export{r as diagram};
|