@rynx-ai/daemon 0.1.11-beta.22 → 0.1.11-beta.23
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.
|
@@ -111,7 +111,11 @@ export class HostConversationRuntime {
|
|
|
111
111
|
const unsteer = input.steer?.subscribe((text) => {
|
|
112
112
|
if (!runId || terminal)
|
|
113
113
|
return;
|
|
114
|
-
|
|
114
|
+
// `session.run` is the only message-input operation. The Host reuses
|
|
115
|
+
// `runId` while this Turn is active and lets the native runtime choose
|
|
116
|
+
// turn/steer; callers do not select a separate steering RPC.
|
|
117
|
+
void this.host.sessions.run({ sessionId: input.threadId, message: text })
|
|
118
|
+
.catch(() => undefined);
|
|
115
119
|
});
|
|
116
120
|
input.signal?.addEventListener("abort", interrupt, { once: true });
|
|
117
121
|
const generator = (async function* () {
|
|
@@ -126958,7 +126958,7 @@ var HostConversationRuntime = class {
|
|
|
126958
126958
|
}
|
|
126959
126959
|
const unsteer = input.steer?.subscribe((text) => {
|
|
126960
126960
|
if (!runId || terminal) return;
|
|
126961
|
-
void this.host.sessions.
|
|
126961
|
+
void this.host.sessions.run({ sessionId: input.threadId, message: text }).catch(() => void 0);
|
|
126962
126962
|
});
|
|
126963
126963
|
input.signal?.addEventListener("abort", interrupt, { once: true });
|
|
126964
126964
|
const generator = (async function* () {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AdmissionReservation, type AgentSpec, type AgentCapabilities, type AgentRuntimeId, type AgentSessionStore, type ConversationRuntime, type ResolvedExecutionSnapshot, type SessionRegistry, type SessionWorkspaceSnapshot } from "@rynx-ai/core";
|
|
2
|
-
import { type PluginAgentSummary, type PluginHostEvent, type PluginResolvedSessionExecution, type PluginSessionExecutionSnapshot, type PluginSessionInteractionResolveDisposition } from "@rynx-ai/plugin-sdk";
|
|
2
|
+
import { type PluginAgentSummary, type PluginHostEvent, type PluginSessionActivitySnapshot, type PluginResolvedSessionExecution, type PluginSessionExecutionSnapshot, type PluginSessionInteractionResolveDisposition } from "@rynx-ai/plugin-sdk";
|
|
3
3
|
import type { SessionInteractionResolution } from "@rynx-ai/protocol";
|
|
4
4
|
import { PluginRunnerError } from "@rynx-ai/plugin-runner";
|
|
5
5
|
/** Leaves ample room for the RPC envelope below the runner's 1 MiB line cap. */
|
|
@@ -52,6 +52,7 @@ export interface PluginHostServices {
|
|
|
52
52
|
reasoningEffort: string | null;
|
|
53
53
|
}): Promise<void>;
|
|
54
54
|
};
|
|
55
|
+
sessionActivity(sessionId: string): PluginSessionActivitySnapshot | Promise<PluginSessionActivitySnapshot>;
|
|
55
56
|
interruptSession?(sessionId: string): Promise<boolean>;
|
|
56
57
|
terminateSession?(sessionId: string): Promise<boolean>;
|
|
57
58
|
resolveSessionInteraction?(sessionId: string, interactionId: string, resolution: SessionInteractionResolution): Promise<{
|
|
@@ -124,10 +125,9 @@ export declare class PluginHostRpc {
|
|
|
124
125
|
private runSessionAdmitted;
|
|
125
126
|
private pumpRun;
|
|
126
127
|
private releaseRun;
|
|
127
|
-
private steerSession;
|
|
128
128
|
private interruptRun;
|
|
129
|
+
private sessionActivity;
|
|
129
130
|
private interruptWon;
|
|
130
|
-
private activeRun;
|
|
131
131
|
private activeRunByIdentity;
|
|
132
132
|
private getBinding;
|
|
133
133
|
private listBindings;
|
package/dist/plugin-host-rpc.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash, randomUUID } from "node:crypto";
|
|
2
2
|
import { realpath, stat } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { AgentRuntimeError, agentSpecSchema, resolvedExecutionSnapshotSchema, sessionWorkspaceSnapshotSchema,
|
|
4
|
+
import { AgentRuntimeError, agentSpecSchema, resolvedExecutionSnapshotSchema, sessionWorkspaceSnapshotSchema, } from "@rynx-ai/core";
|
|
5
5
|
import { PLUGIN_HOST_MAX_ACTIVE_RUNS, } from "@rynx-ai/plugin-sdk";
|
|
6
6
|
import { PluginRunnerError } from "@rynx-ai/plugin-runner";
|
|
7
7
|
import { ensurePluginSessionLaunch, replayPluginSessionLaunch, SessionLaunchOperationConflictError, SessionLaunchOperationTargetDeletedError, } from "./session-launch-operations.js";
|
|
@@ -14,6 +14,57 @@ const MAX_PLUGIN_RUN_FINAL_RESPONSE_BYTES = 64 * 1024;
|
|
|
14
14
|
const MAX_DELTA_CHUNK_CODE_UNITS = 64 * 1024;
|
|
15
15
|
const SESSION_INTERACTION_RESOLUTION_MAX_BYTES = 128 * 1024;
|
|
16
16
|
const AGENT_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/;
|
|
17
|
+
/**
|
|
18
|
+
* Buffers messages that arrive while the first `session.run` is still bringing
|
|
19
|
+
* up its native Turn. Once Core subscribes, later messages are delivered
|
|
20
|
+
* through the same input channel. After that subscription closes, this Run no
|
|
21
|
+
* longer accepts input; the caller waits for release and opens the next Run.
|
|
22
|
+
*/
|
|
23
|
+
class PluginRunInputController {
|
|
24
|
+
listener;
|
|
25
|
+
pending = new Map();
|
|
26
|
+
subscribed = false;
|
|
27
|
+
closed = false;
|
|
28
|
+
enqueue(text) {
|
|
29
|
+
if (this.closed || (this.subscribed && !this.listener)) {
|
|
30
|
+
return { accepted: false, cancel: () => undefined };
|
|
31
|
+
}
|
|
32
|
+
if (this.listener) {
|
|
33
|
+
this.listener(text);
|
|
34
|
+
return { accepted: true, cancel: () => undefined };
|
|
35
|
+
}
|
|
36
|
+
const token = Symbol("plugin-run-input");
|
|
37
|
+
this.pending.set(token, text);
|
|
38
|
+
return {
|
|
39
|
+
accepted: true,
|
|
40
|
+
cancel: () => {
|
|
41
|
+
this.pending.delete(token);
|
|
42
|
+
},
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
subscribe(listener) {
|
|
46
|
+
if (this.closed)
|
|
47
|
+
return () => undefined;
|
|
48
|
+
if (this.listener) {
|
|
49
|
+
throw new Error("plugin Run input already has a subscriber");
|
|
50
|
+
}
|
|
51
|
+
this.subscribed = true;
|
|
52
|
+
this.listener = listener;
|
|
53
|
+
const queued = [...this.pending.values()];
|
|
54
|
+
this.pending.clear();
|
|
55
|
+
for (const text of queued)
|
|
56
|
+
listener(text);
|
|
57
|
+
return () => {
|
|
58
|
+
if (this.listener === listener)
|
|
59
|
+
this.listener = undefined;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
close() {
|
|
63
|
+
this.closed = true;
|
|
64
|
+
this.listener = undefined;
|
|
65
|
+
this.pending.clear();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
17
68
|
/**
|
|
18
69
|
* One authenticated plugin's Host RPC surface.
|
|
19
70
|
*
|
|
@@ -90,8 +141,8 @@ export class PluginHostRpc {
|
|
|
90
141
|
return await this.ensureSession(params);
|
|
91
142
|
case "session.run":
|
|
92
143
|
return await this.runSession(params, signal);
|
|
93
|
-
case "session.
|
|
94
|
-
return this.
|
|
144
|
+
case "session.activity.get":
|
|
145
|
+
return await this.sessionActivity(params);
|
|
95
146
|
case "session.interrupt":
|
|
96
147
|
return await this.interruptRun(params);
|
|
97
148
|
case "session.interaction.resolve":
|
|
@@ -301,6 +352,46 @@ export class PluginHostRpc {
|
|
|
301
352
|
const input = record(params);
|
|
302
353
|
const sessionId = requiredSessionId(input);
|
|
303
354
|
const operationId = optionalString(input.operationId, "operationId", 512);
|
|
355
|
+
const message = requiredText(input.message, "message", MAX_MESSAGE_LENGTH);
|
|
356
|
+
let session = this.ownedSession(sessionId);
|
|
357
|
+
if (operationId) {
|
|
358
|
+
const replayed = this.activeRunsByOperation.get(operationId);
|
|
359
|
+
if (replayed) {
|
|
360
|
+
if (replayed.sessionId !== sessionId) {
|
|
361
|
+
throw new PluginHostCallError("RUN_ALREADY_ACTIVE", `operation already belongs to another active Session: ${operationId}`, true);
|
|
362
|
+
}
|
|
363
|
+
return await waitForHostPromise(replayed.started, signal);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const active = this.activeSessionRuns.get(sessionId);
|
|
367
|
+
if (active) {
|
|
368
|
+
const queued = active.input.enqueue(message);
|
|
369
|
+
if (!queued.accepted) {
|
|
370
|
+
// The response reached its terminal boundary before Host cleanup won
|
|
371
|
+
// the scheduling race. Wait for that old Run to leave the Session slot,
|
|
372
|
+
// then submit this message as a new Turn with a new response identity.
|
|
373
|
+
await waitForHostPromise(active.settled, signal);
|
|
374
|
+
throwIfHostCallAborted(signal);
|
|
375
|
+
return await this.runSessionAdmitted(params, signal);
|
|
376
|
+
}
|
|
377
|
+
if (operationId) {
|
|
378
|
+
active.operationIds.add(operationId);
|
|
379
|
+
this.activeRunsByOperation.set(operationId, active);
|
|
380
|
+
}
|
|
381
|
+
try {
|
|
382
|
+
// Reuse the current Run identity. Core already owns its response stream;
|
|
383
|
+
// the buffered input will become turn/steer once that stream subscribes.
|
|
384
|
+
return await waitForHostPromise(active.started, signal);
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
queued.cancel();
|
|
388
|
+
if (operationId && this.activeRunsByOperation.get(operationId) === active) {
|
|
389
|
+
this.activeRunsByOperation.delete(operationId);
|
|
390
|
+
active.operationIds.delete(operationId);
|
|
391
|
+
}
|
|
392
|
+
throw error;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
304
395
|
const modelProvided = input.model !== undefined;
|
|
305
396
|
const requestedModel = input.model === null || input.model === ""
|
|
306
397
|
? null
|
|
@@ -309,17 +400,9 @@ export class PluginHostRpc {
|
|
|
309
400
|
const requestedReasoningEffort = input.reasoningEffort === null || input.reasoningEffort === ""
|
|
310
401
|
? null
|
|
311
402
|
: optionalString(input.reasoningEffort, "reasoningEffort", 64);
|
|
312
|
-
let session = this.ownedSession(sessionId);
|
|
313
|
-
if (operationId && this.activeRunsByOperation.has(operationId)) {
|
|
314
|
-
throw new PluginHostCallError("RUN_ALREADY_ACTIVE", `operation already has an active run: ${operationId}`, true);
|
|
315
|
-
}
|
|
316
|
-
if (this.activeSessionRuns.has(sessionId)) {
|
|
317
|
-
throw new PluginHostCallError("RUN_ALREADY_ACTIVE", `session already has an active run: ${sessionId}`, true);
|
|
318
|
-
}
|
|
319
403
|
if (this.activeRuns.size >= PLUGIN_HOST_MAX_ACTIVE_RUNS) {
|
|
320
404
|
throw new PluginHostCallError("RUN_LIMIT", "plugin has too many active session runs", true);
|
|
321
405
|
}
|
|
322
|
-
const message = requiredText(input.message, "message", MAX_MESSAGE_LENGTH);
|
|
323
406
|
const nextModel = modelProvided ? requestedModel ?? null : session.execution.model;
|
|
324
407
|
const nextReasoningEffort = reasoningEffortProvided
|
|
325
408
|
? requestedReasoningEffort ?? null
|
|
@@ -340,32 +423,54 @@ export class PluginHostRpc {
|
|
|
340
423
|
throwIfHostCallAborted(signal);
|
|
341
424
|
}
|
|
342
425
|
signal?.addEventListener("abort", cancel, { once: true });
|
|
343
|
-
const
|
|
426
|
+
const runInput = new PluginRunInputController();
|
|
344
427
|
const runId = randomUUID();
|
|
428
|
+
let resolveStarted;
|
|
429
|
+
let rejectStarted;
|
|
430
|
+
const startedResult = new Promise((resolve, reject) => {
|
|
431
|
+
resolveStarted = resolve;
|
|
432
|
+
rejectStarted = reject;
|
|
433
|
+
});
|
|
434
|
+
// The initiating RPC observes startup directly below. This promise exists
|
|
435
|
+
// for concurrent/replayed calls, so retain its rejection without creating
|
|
436
|
+
// an unhandled-rejection when there are none.
|
|
437
|
+
void startedResult.catch(() => undefined);
|
|
438
|
+
let resolveSettled;
|
|
439
|
+
const settled = new Promise((resolve) => {
|
|
440
|
+
resolveSettled = resolve;
|
|
441
|
+
});
|
|
345
442
|
const run = {
|
|
346
443
|
runId,
|
|
347
444
|
sessionId,
|
|
348
|
-
operationId,
|
|
445
|
+
operationIds: new Set(operationId ? [operationId] : []),
|
|
349
446
|
interruptRequested: false,
|
|
350
447
|
abort,
|
|
351
|
-
|
|
448
|
+
input: runInput,
|
|
449
|
+
started: startedResult,
|
|
450
|
+
startupSettled: false,
|
|
451
|
+
resolveStarted,
|
|
452
|
+
rejectStarted,
|
|
453
|
+
settled,
|
|
454
|
+
resolveSettled,
|
|
352
455
|
};
|
|
353
456
|
this.activeRuns.set(runId, run);
|
|
354
457
|
this.activeSessionRuns.set(sessionId, run);
|
|
355
458
|
if (operationId)
|
|
356
459
|
this.activeRunsByOperation.set(operationId, run);
|
|
357
|
-
let
|
|
460
|
+
let startedExecution;
|
|
358
461
|
try {
|
|
359
|
-
|
|
462
|
+
startedExecution = await this.services.conversationRuntime.runLive({
|
|
360
463
|
message,
|
|
361
464
|
threadId: sessionId,
|
|
362
465
|
workspace: session.workspace,
|
|
363
466
|
execution: session.execution,
|
|
364
467
|
signal: abort.signal,
|
|
365
|
-
steer,
|
|
468
|
+
steer: runInput,
|
|
366
469
|
});
|
|
367
470
|
}
|
|
368
471
|
catch (error) {
|
|
472
|
+
run.startupSettled = true;
|
|
473
|
+
run.rejectStarted(error);
|
|
369
474
|
this.releaseRun(run);
|
|
370
475
|
throw error;
|
|
371
476
|
}
|
|
@@ -374,20 +479,28 @@ export class PluginHostRpc {
|
|
|
374
479
|
}
|
|
375
480
|
if (signal?.aborted || this.disposed || this.activeRuns.get(runId) !== run) {
|
|
376
481
|
abort.abort(signal?.reason);
|
|
482
|
+
const error = signal?.aborted
|
|
483
|
+
? new PluginHostCallError("REQUEST_CANCELLED", "plugin host request was cancelled")
|
|
484
|
+
: new PluginHostCallError("HOST_CLOSED", "plugin host is closed");
|
|
485
|
+
run.startupSettled = true;
|
|
486
|
+
run.rejectStarted(error);
|
|
377
487
|
this.releaseRun(run);
|
|
378
488
|
throwIfHostCallAborted(signal);
|
|
379
|
-
throw
|
|
489
|
+
throw error;
|
|
380
490
|
}
|
|
381
|
-
|
|
382
|
-
// emitted. `runLive` has already subscribed, so no agent event is lost.
|
|
383
|
-
setImmediate(() => void this.pumpRun(run, started.generator));
|
|
384
|
-
return {
|
|
491
|
+
const result = {
|
|
385
492
|
runId,
|
|
386
493
|
sessionId,
|
|
387
|
-
provider:
|
|
388
|
-
model:
|
|
389
|
-
authSource:
|
|
494
|
+
provider: startedExecution.provider,
|
|
495
|
+
model: startedExecution.model,
|
|
496
|
+
authSource: startedExecution.authSource,
|
|
390
497
|
};
|
|
498
|
+
run.startupSettled = true;
|
|
499
|
+
run.resolveStarted(result);
|
|
500
|
+
// Let the RPC transport write the request response before stream events are
|
|
501
|
+
// emitted. `runLive` has already subscribed, so no agent event is lost.
|
|
502
|
+
setImmediate(() => void this.pumpRun(run, startedExecution.generator));
|
|
503
|
+
return result;
|
|
391
504
|
}
|
|
392
505
|
async pumpRun(run, generator) {
|
|
393
506
|
let terminalFailure;
|
|
@@ -469,28 +582,52 @@ export class PluginHostRpc {
|
|
|
469
582
|
}
|
|
470
583
|
}
|
|
471
584
|
releaseRun(run) {
|
|
585
|
+
run.input.close();
|
|
586
|
+
if (!run.startupSettled) {
|
|
587
|
+
run.startupSettled = true;
|
|
588
|
+
run.rejectStarted(new PluginHostCallError("HOST_CLOSED", "plugin Host closed the active Run"));
|
|
589
|
+
}
|
|
472
590
|
if (this.activeRuns.get(run.runId) === run)
|
|
473
591
|
this.activeRuns.delete(run.runId);
|
|
474
592
|
if (this.activeSessionRuns.get(run.sessionId) === run) {
|
|
475
593
|
this.activeSessionRuns.delete(run.sessionId);
|
|
476
594
|
}
|
|
477
|
-
|
|
478
|
-
this.activeRunsByOperation.
|
|
595
|
+
for (const operationId of run.operationIds) {
|
|
596
|
+
if (this.activeRunsByOperation.get(operationId) === run) {
|
|
597
|
+
this.activeRunsByOperation.delete(operationId);
|
|
598
|
+
}
|
|
479
599
|
}
|
|
480
|
-
|
|
481
|
-
steerSession(params) {
|
|
482
|
-
const input = record(params);
|
|
483
|
-
const run = this.activeRun(input);
|
|
484
|
-
const text = requiredText(input.text, "text", MAX_MESSAGE_LENGTH);
|
|
485
|
-
return { delivered: run.steer.send(text) };
|
|
600
|
+
run.resolveSettled();
|
|
486
601
|
}
|
|
487
602
|
async interruptRun(params) {
|
|
488
603
|
const input = record(params);
|
|
489
|
-
const run = this.activeRunByIdentity(input);
|
|
490
604
|
const forceAfterMs = optionalPositiveNumber(input.forceAfterMs, "forceAfterMs");
|
|
491
605
|
if (forceAfterMs !== undefined && forceAfterMs > 30_000) {
|
|
492
606
|
throw new PluginHostCallError("INVALID_PARAMS", "forceAfterMs must not exceed 30000");
|
|
493
607
|
}
|
|
608
|
+
const sessionId = optionalString(input.sessionId, "sessionId", 128);
|
|
609
|
+
const runId = optionalString(input.runId, "runId", 128);
|
|
610
|
+
const operationId = optionalString(input.operationId, "operationId", 512);
|
|
611
|
+
if ((sessionId ? 1 : 0) + (runId ? 1 : 0) + (operationId ? 1 : 0) !== 1) {
|
|
612
|
+
throw new PluginHostCallError("INVALID_PARAMS", "exactly one of sessionId, runId, or operationId is required");
|
|
613
|
+
}
|
|
614
|
+
let run;
|
|
615
|
+
if (sessionId) {
|
|
616
|
+
this.ownedSession(sessionId);
|
|
617
|
+
run = this.activeSessionRuns.get(sessionId);
|
|
618
|
+
if (!run) {
|
|
619
|
+
const graceful = this.services.interruptSession
|
|
620
|
+
? Promise.resolve().then(() => this.services.interruptSession(sessionId))
|
|
621
|
+
: Promise.resolve(false);
|
|
622
|
+
const interrupted = forceAfterMs === undefined
|
|
623
|
+
? await graceful
|
|
624
|
+
: await forceStoppedInterrupt(graceful, forceAfterMs, () => this.services.terminateSession?.(sessionId) ?? Promise.resolve(false));
|
|
625
|
+
return { interrupted };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
else {
|
|
629
|
+
run = this.activeRunByIdentity(input);
|
|
630
|
+
}
|
|
494
631
|
if (run.interruptResult) {
|
|
495
632
|
return { interrupted: await run.interruptResult };
|
|
496
633
|
}
|
|
@@ -529,6 +666,24 @@ export class PluginHostRpc {
|
|
|
529
666
|
throw error;
|
|
530
667
|
}
|
|
531
668
|
}
|
|
669
|
+
async sessionActivity(params) {
|
|
670
|
+
const sessionId = requiredSessionId(params);
|
|
671
|
+
this.ownedSession(sessionId);
|
|
672
|
+
const snapshot = structuredClone(await this.services.sessionActivity(sessionId));
|
|
673
|
+
const activeRun = this.activeSessionRuns.get(sessionId);
|
|
674
|
+
const waiting = snapshot.pendingInteractions.length > 0;
|
|
675
|
+
const status = waiting
|
|
676
|
+
? "waiting"
|
|
677
|
+
: activeRun
|
|
678
|
+
? "running"
|
|
679
|
+
: snapshot.status;
|
|
680
|
+
const startup = Boolean(activeRun && snapshot.activeResponseIds.length === 0 && !waiting);
|
|
681
|
+
return {
|
|
682
|
+
...snapshot,
|
|
683
|
+
status,
|
|
684
|
+
...(startup ? { statusKind: "startup" } : {}),
|
|
685
|
+
};
|
|
686
|
+
}
|
|
532
687
|
async interruptWon(run) {
|
|
533
688
|
if (!run.interruptRequested)
|
|
534
689
|
return false;
|
|
@@ -536,13 +691,6 @@ export class PluginHostRpc {
|
|
|
536
691
|
return true;
|
|
537
692
|
return run.interruptResult.catch(() => false);
|
|
538
693
|
}
|
|
539
|
-
activeRun(input) {
|
|
540
|
-
const runId = requiredString(input.runId, "runId", 128);
|
|
541
|
-
const run = this.activeRuns.get(runId);
|
|
542
|
-
if (!run)
|
|
543
|
-
throw new PluginHostCallError("RUN_NOT_FOUND", `active run not found: ${runId}`);
|
|
544
|
-
return run;
|
|
545
|
-
}
|
|
546
694
|
activeRunByIdentity(input) {
|
|
547
695
|
const runId = optionalString(input.runId, "runId", 128);
|
|
548
696
|
const operationId = optionalString(input.operationId, "operationId", 512);
|
|
@@ -692,6 +840,24 @@ function throwIfHostCallAborted(signal) {
|
|
|
692
840
|
return;
|
|
693
841
|
throw new PluginHostCallError("REQUEST_CANCELLED", "plugin host request was cancelled");
|
|
694
842
|
}
|
|
843
|
+
async function waitForHostPromise(promise, signal) {
|
|
844
|
+
throwIfHostCallAborted(signal);
|
|
845
|
+
if (!signal)
|
|
846
|
+
return await promise;
|
|
847
|
+
return await new Promise((resolve, reject) => {
|
|
848
|
+
const aborted = () => {
|
|
849
|
+
reject(new PluginHostCallError("REQUEST_CANCELLED", "plugin host request was cancelled"));
|
|
850
|
+
};
|
|
851
|
+
signal.addEventListener("abort", aborted, { once: true });
|
|
852
|
+
void promise.then((value) => {
|
|
853
|
+
signal.removeEventListener("abort", aborted);
|
|
854
|
+
resolve(value);
|
|
855
|
+
}, (error) => {
|
|
856
|
+
signal.removeEventListener("abort", aborted);
|
|
857
|
+
reject(error);
|
|
858
|
+
});
|
|
859
|
+
});
|
|
860
|
+
}
|
|
695
861
|
export class PluginHostCallError extends PluginRunnerError {
|
|
696
862
|
retryable;
|
|
697
863
|
data;
|
|
@@ -714,6 +880,12 @@ function toHostCallError(error) {
|
|
|
714
880
|
// not be brought up, so callers may fail without quarantining capacity.
|
|
715
881
|
return new PluginHostCallError("LIVE_SESSION_UNAVAILABLE", error.message, false);
|
|
716
882
|
}
|
|
883
|
+
if (error instanceof AgentRuntimeError) {
|
|
884
|
+
// Native lifecycle failures already carry a stable phase code. Preserve it
|
|
885
|
+
// across the plugin-host boundary instead of erasing it behind the generic
|
|
886
|
+
// HOST_CALL_FAILED wrapper.
|
|
887
|
+
return new PluginHostCallError(error.code, error.message, false);
|
|
888
|
+
}
|
|
717
889
|
if (error instanceof SessionLaunchOperationConflictError) {
|
|
718
890
|
return new PluginHostCallError(error.code, error.message, false);
|
|
719
891
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rynx-ai/daemon",
|
|
3
|
-
"version": "0.1.11-beta.
|
|
3
|
+
"version": "0.1.11-beta.23",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/rynx-ai/rynx.git",
|
|
@@ -50,17 +50,17 @@
|
|
|
50
50
|
"pm2": "^6.0.0",
|
|
51
51
|
"tar": "^7.5.19",
|
|
52
52
|
"ws": "^8.21.0",
|
|
53
|
-
"@rynx-ai/
|
|
54
|
-
"@rynx-ai/
|
|
55
|
-
"@rynx-ai/
|
|
56
|
-
"@rynx-ai/plugin-sdk": "0.1.11-beta.
|
|
57
|
-
"@rynx-ai/protocol": "0.1.11-beta.
|
|
58
|
-
"@rynx-ai/remote-runtime-client": "0.1.11-beta.
|
|
59
|
-
"@rynx-ai/server": "0.1.11-beta.
|
|
53
|
+
"@rynx-ai/plugin-runner": "0.1.11-beta.23",
|
|
54
|
+
"@rynx-ai/core": "0.1.11-beta.23",
|
|
55
|
+
"@rynx-ai/emulator": "0.1.11-beta.23",
|
|
56
|
+
"@rynx-ai/plugin-sdk": "0.1.11-beta.23",
|
|
57
|
+
"@rynx-ai/protocol": "0.1.11-beta.23",
|
|
58
|
+
"@rynx-ai/remote-runtime-client": "0.1.11-beta.23",
|
|
59
|
+
"@rynx-ai/server": "0.1.11-beta.23"
|
|
60
60
|
},
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@types/ws": "^8.18.1",
|
|
63
|
-
"@rynx-ai/plugin-channel-lark": "0.1.11-beta.
|
|
63
|
+
"@rynx-ai/plugin-channel-lark": "0.1.11-beta.23"
|
|
64
64
|
},
|
|
65
65
|
"scripts": {
|
|
66
66
|
"build": "rm -rf dist bundled-plugins && tsc -p tsconfig.json && chmod +x dist/index-daemon.js && node ../../scripts/stage-bundled-plugins.mjs",
|