@yefengr/remote-pi 0.7.0 → 0.7.2
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/actions/handlers.d.ts +4 -0
- package/dist/actions/handlers.js +16 -13
- package/dist/actions/handlers.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +244 -32
- package/dist/index.js.map +1 -1
- package/dist/protocol/types.d.ts +4 -0
- package/dist/protocol/v2/schemas.d.ts +24 -1
- package/dist/protocol/v2/schemas.js +23 -5
- package/dist/protocol/v2/schemas.js.map +1 -1
- package/dist/protocol/v2/session_state.d.ts +1 -1
- package/dist/timeline/v2_service.d.ts +9 -1
- package/dist/timeline/v2_service.js +41 -3
- package/dist/timeline/v2_service.js.map +1 -1
- package/dist/transport/peer_channel.js +2 -1
- package/dist/transport/peer_channel.js.map +1 -1
- package/package.json +1 -1
|
@@ -118,5 +118,9 @@ export declare function handleSessionCompact(ctx: ActionCtx | null, sender: Acti
|
|
|
118
118
|
export declare function handleSessionNew(ctx: ActionCtx | null, sender: ActionReplySender, msg: SessionNewMsg, onReplaced?: (freshCtx: ActionCtx) => void): Promise<boolean>;
|
|
119
119
|
export declare function handleThinkingSet(pi: ActionPi, sender: ActionReplySender, msg: ThinkingSetMsg): void;
|
|
120
120
|
export declare function handleModelSet(pi: ActionPi, ctx: ActionCtx | null, reg: ActionModelRegistry, sender: ActionReplySender, msg: ModelSetMsg, onPersist?: (provider: string, modelId: string) => void): Promise<void>;
|
|
121
|
+
export declare function getModelsList(ctx: ActionCtx | null, reg: ActionModelRegistry, currentNameOrId?: string): {
|
|
122
|
+
models: WireModel[];
|
|
123
|
+
current?: WireModel;
|
|
124
|
+
};
|
|
121
125
|
export declare function handleListModels(ctx: ActionCtx | null, reg: ActionModelRegistry, sender: ActionReplySender, msg: ListModelsMsg): void;
|
|
122
126
|
export {};
|
package/dist/actions/handlers.js
CHANGED
|
@@ -130,23 +130,26 @@ export async function handleModelSet(pi, ctx, reg, sender, msg, onPersist) {
|
|
|
130
130
|
onPersist?.(model.provider, model.id);
|
|
131
131
|
});
|
|
132
132
|
}
|
|
133
|
+
export function getModelsList(ctx, reg, currentNameOrId) {
|
|
134
|
+
// Prefer Pi's LIVE session registry when available so the app sees models
|
|
135
|
+
// registered dynamically by extensions via `pi.registerProvider(...)`.
|
|
136
|
+
// Fall back to remote-pi's own disk-backed registry when no ctx exists.
|
|
137
|
+
const liveReg = ctx?.modelRegistry ?? reg;
|
|
138
|
+
liveReg.refresh();
|
|
139
|
+
const available = liveReg.getAvailable();
|
|
140
|
+
const models = available.map(wireFromModel);
|
|
141
|
+
const liveCurrent = ctx?.getModel?.();
|
|
142
|
+
const cachedMatches = currentNameOrId
|
|
143
|
+
? available.filter((model) => model.id === currentNameOrId || model.name === currentNameOrId)
|
|
144
|
+
: [];
|
|
145
|
+
const current = liveCurrent ?? (cachedMatches.length === 1 ? cachedMatches[0] : undefined);
|
|
146
|
+
return { models, ...(current ? { current: wireFromModel(current) } : {}) };
|
|
147
|
+
}
|
|
133
148
|
export function handleListModels(ctx, reg, sender, msg) {
|
|
134
149
|
// refresh() can throw if `models.json` is malformed — wrap in try so the
|
|
135
150
|
// app gets an explicit error reply instead of a silent drop.
|
|
136
151
|
try {
|
|
137
|
-
|
|
138
|
-
// registered dynamically by extensions via `pi.registerProvider(...)`.
|
|
139
|
-
// Fall back to remote-pi's own disk-backed registry when no ctx exists.
|
|
140
|
-
const liveReg = ctx?.modelRegistry ?? reg;
|
|
141
|
-
liveReg.refresh();
|
|
142
|
-
const models = liveReg.getAvailable().map(wireFromModel);
|
|
143
|
-
const current = ctx?.getModel?.();
|
|
144
|
-
sender.send({
|
|
145
|
-
type: "models_list",
|
|
146
|
-
in_reply_to: msg.id,
|
|
147
|
-
models,
|
|
148
|
-
current: current ? wireFromModel(current) : undefined,
|
|
149
|
-
});
|
|
152
|
+
sender.send({ type: "models_list", in_reply_to: msg.id, ...getModelsList(ctx, reg) });
|
|
150
153
|
}
|
|
151
154
|
catch (e) {
|
|
152
155
|
sender.send({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/actions/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AA2FH;wDACwD;AACxD,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,OAAO;QACL,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS,EAAE,KAAK,CAAC,SAAS;QAC1B,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,gEAAgE;QAChE,2EAA2E;QAC3E,wDAAwD;QACxD,MAAM,EAAE,KAAK,CAAC,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK;KAChD,CAAC;AACJ,CAAC;AAED,8EAA8E;AAE9E,SAAS,EAAE,CAAC,MAAyB,EAAE,GAAmB,EAAE,MAAkB;IAC5E,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;AAClE,CAAC;AAED,SAAS,IAAI,CACX,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,GAAY;IAEZ,MAAM,KAAK,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC/D,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;AAC5E,CAAC;AAED,qEAAqE;AACrE,SAAS,OAAO,CACd,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,IAAgB;IAEhB,IAAI,CAAC;QACH,IAAI,EAAE,CAAC;QACP,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,gEAAgE;AAChE,KAAK,UAAU,QAAQ,CACrB,MAAyB,EACzB,GAAmB,EACnB,MAAkB,EAClB,IAAyB;IAEzB,IAAI,CAAC;QACH,MAAM,IAAI,EAAE,CAAC;QACb,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACxB,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAUD,MAAM,UAAU,oBAAoB,CAClC,GAAqB,EACrB,MAAyB,EACzB,GAAsB;IAEtB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,iBAAiB,EAAE,GAAG,EAAE;QAC3C,IAAI,CAAC,GAAG,EAAE,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QAClF,yEAAyE;QACzE,yEAAyE;QACzE,4EAA4E;QAC5E,iEAAiE;QACjE,GAAG,CAAC,OAAO,CAAC;YACV,kBAAkB,EAChB,kGAAkG;SACrG,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,GAAqB,EACrB,MAAyB,EACzB,GAAkB,EAClB,UAA0C;IAE1C,wEAAwE;IACxE,2EAA2E;IAC3E,4EAA4E;IAC5E,uEAAuE;IACvE,OAAO,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,IAAI,EAAE;QACrD,IAAI,CAAC,GAAG,EAAE,UAAU;YAAE,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;QACrF,2EAA2E;QAC3E,mEAAmE;QACnE,sEAAsE;QACtE,0EAA0E;QAC1E,uEAAuE;QACvE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,UAAU,CAAC;YAClC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,GAAG,UAAU,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;SAC7D,CAAC,CAAC;QACH,qEAAqE;QACrE,kEAAkE;QAClE,iEAAiE;QACjE,IAAI,MAAM,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,EAAY,EACZ,MAAyB,EACzB,GAAmB;IAEnB,OAAO,CAAC,MAAM,EAAE,GAAG,EAAE,cAAc,EAAE,GAAG,EAAE;QACxC,EAAE,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,GAAqB,EACrB,GAAwB,EACxB,MAAyB,EACzB,GAAgB,EAChB,SAAuD;IAEvD,MAAM,QAAQ,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,IAAI,EAAE;QAClD,0EAA0E;QAC1E,uEAAuE;QACvE,wEAAwE;QACxE,MAAM,OAAO,GAAG,GAAG,EAAE,aAAa,IAAI,GAAG,CAAC;QAC1C,+DAA+D;QAC/D,OAAO,CAAC,OAAO,EAAE,CAAC;QAClB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,KAAK,CAAC,UAAU,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,QAAQ,mBAAmB,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO;YAAE,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACnE,wEAAwE;QACxE,wEAAwE;QACxE,yEAAyE;QACzE,qEAAqE;QACrE,0EAA0E;QAC1E,2EAA2E;QAC3E,SAAS,EAAE,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,aAAa,CAC3B,GAAqB,EACrB,GAAwB,EACxB,eAAwB;IAExB,0EAA0E;IAC1E,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,OAAO,GAAG,GAAG,EAAE,aAAa,IAAI,GAAG,CAAC;IAC1C,OAAO,CAAC,OAAO,EAAE,CAAC;IAClB,MAAM,SAAS,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IACzC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IAC5C,MAAM,WAAW,GAAG,GAAG,EAAE,QAAQ,EAAE,EAAE,CAAC;IACtC,MAAM,aAAa,GAAG,eAAe;QACnC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,eAAe,IAAI,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC;QAC7F,CAAC,CAAC,EAAE,CAAC;IACP,MAAM,OAAO,GAAG,WAAW,IAAI,CAAC,aAAa,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IAC3F,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,gBAAgB,CAC9B,GAAqB,EACrB,GAAwB,EACxB,MAAyB,EACzB,GAAkB;IAElB,yEAAyE;IACzE,6DAA6D;IAC7D,IAAI,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,WAAW,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACxF,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CAAC,IAAI,CAAC;YACV,IAAI,EAAE,OAAO;YACb,WAAW,EAAE,GAAG,CAAC,EAAE;YACnB,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;SACpD,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,12 @@ type BufferMsg = {
|
|
|
59
59
|
* `role:"compaction"` marker pushed in `session_compact`. */
|
|
60
60
|
tokensBefore?: number;
|
|
61
61
|
};
|
|
62
|
+
export declare const MAX_QUEUED_IMAGE_BYTES_PER_OWNER: number;
|
|
63
|
+
export declare const MAX_QUEUED_IMAGE_BYTES_GLOBAL: number;
|
|
64
|
+
type QueuedImageLimits = {
|
|
65
|
+
perOwner: number;
|
|
66
|
+
global: number;
|
|
67
|
+
};
|
|
62
68
|
type MeshEnvelope = {
|
|
63
69
|
id: string;
|
|
64
70
|
from: string;
|
|
@@ -66,6 +72,8 @@ type MeshEnvelope = {
|
|
|
66
72
|
body: unknown;
|
|
67
73
|
};
|
|
68
74
|
export declare function _getTimelinePublishedEventsForTest(): unknown[];
|
|
75
|
+
/** Test-only: lower the image budget without allocating multi-megabyte frames. */
|
|
76
|
+
export declare function _setQueuedImageLimitsForTest(limits: QueuedImageLimits | null): void;
|
|
69
77
|
/** Test-only override of the message buffer. */
|
|
70
78
|
/**
|
|
71
79
|
* Test-only: emulate what `/remote-pi` does on the returning-user path
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import { addPeer, getOrCreateEd25519Keypair, KeyringUnavailableError, PairedIden
|
|
|
36
36
|
import { MeshClient } from "./mesh/client.js";
|
|
37
37
|
import { canonicalizeEd25519PublicKey, decodeEd25519PublicKey, publicKeyFingerprint, } from "./mesh/encoding.js";
|
|
38
38
|
import { SelfRevoke } from "./mesh/self_revoke.js";
|
|
39
|
-
import { decodeClientFrameV2, encodeServerFrameV2, parseTimelinePartialV2, } from "./protocol/v2/index.js";
|
|
39
|
+
import { decodeClientFrameV2, encodeServerFrameV2, fingerprintV2Payload, MAX_FRAME_BYTES, parseTimelinePartialV2, } from "./protocol/v2/index.js";
|
|
40
40
|
import { RelayClient, RoomAlreadyOpenError } from "./transport/relay_client.js";
|
|
41
41
|
import { PlainPeerChannel, V2PeerChannel } from "./transport/peer_channel.js";
|
|
42
42
|
import { TimelineV2Service } from "./timeline/v2_service.js";
|
|
@@ -45,7 +45,7 @@ import { roomIdFor } from "./rooms.js";
|
|
|
45
45
|
import { registerAgentTools } from "./session/tools.js";
|
|
46
46
|
import { formatPeerInventory } from "./session/peer_inventory.js";
|
|
47
47
|
import { MeshNode } from "./session/mesh_node.js";
|
|
48
|
-
import { handleSessionCompact, handleModelSet, handleThinkingSet, handleListModels, } from "./actions/handlers.js";
|
|
48
|
+
import { handleSessionCompact, handleModelSet, handleThinkingSet, handleListModels, getModelsList, } from "./actions/handlers.js";
|
|
49
49
|
import { ensureModelRegistry } from "./actions/registry.js";
|
|
50
50
|
import { ensureGlobalDirs, LOCAL_SESSION_NAME, sessionAuditPath, sessionSockPath, skillsDir, } from "./session/global_config.js";
|
|
51
51
|
import { acquireCwdLock } from "./session/cwd_lock.js";
|
|
@@ -755,7 +755,8 @@ function _ensureV2Service(senderRef) {
|
|
|
755
755
|
const steering = frame.streaming_behavior === "steer";
|
|
756
756
|
const busy = _agentRunActive || _isBusyForQueueDrain() || _v2QueuedDrainScheduled;
|
|
757
757
|
if (!steering && busy) {
|
|
758
|
-
|
|
758
|
+
const queued = _enqueueV2UserMessage(senderRef, frame, correlation);
|
|
759
|
+
return queued === true ? "queued" : queued;
|
|
759
760
|
}
|
|
760
761
|
const previousTurnId = _currentTurnId;
|
|
761
762
|
const seededTurnId = !steering || _currentTurnId === null;
|
|
@@ -772,6 +773,8 @@ function _ensureV2Service(senderRef) {
|
|
|
772
773
|
return true;
|
|
773
774
|
},
|
|
774
775
|
onCancel: (targetId) => _abortCurrentTurn(_lastEventCtx ?? _lastCtx ?? undefined),
|
|
776
|
+
onQueuedMessageClear: (targetId) => _clearV2QueuedUserMessages(senderRef, targetId),
|
|
777
|
+
onListModels: () => getModelsList((_lastEventCtx ?? _lastCtx), ensureModelRegistry((_lastEventCtx ?? _lastCtx)), _currentModel),
|
|
775
778
|
});
|
|
776
779
|
return service;
|
|
777
780
|
}
|
|
@@ -789,6 +792,10 @@ function _routeV2ClientFrameFrom(senderRef, frame) {
|
|
|
789
792
|
const frames = binding.service.handle(frame);
|
|
790
793
|
for (const response of frames)
|
|
791
794
|
binding.channel.sendV2(response);
|
|
795
|
+
if (frame.type === "session_hello") {
|
|
796
|
+
for (const state of _v2QueuedStateFrames(binding.service))
|
|
797
|
+
binding.channel.sendV2(state);
|
|
798
|
+
}
|
|
792
799
|
}
|
|
793
800
|
function _attachV2Peer(relay, appPeerId) {
|
|
794
801
|
_detachPeerChannel(appPeerId);
|
|
@@ -808,6 +815,11 @@ let _queuedItems = [];
|
|
|
808
815
|
const MAX_V2_QUEUED_USERS_PER_OWNER = 128;
|
|
809
816
|
const MAX_V2_QUEUED_USERS = 512;
|
|
810
817
|
const V2_QUEUED_USER_TTL_MS = 5 * 60 * 1000;
|
|
818
|
+
export const MAX_QUEUED_IMAGE_BYTES_PER_OWNER = 8 * 1024 * 1024;
|
|
819
|
+
export const MAX_QUEUED_IMAGE_BYTES_GLOBAL = 32 * 1024 * 1024;
|
|
820
|
+
let _queuedImageBytesGlobal = 0;
|
|
821
|
+
const _queuedImageBytesByOwner = new Map();
|
|
822
|
+
let _queuedImageLimitsForTest = null;
|
|
811
823
|
let _v2QueuedUserMessages = [];
|
|
812
824
|
let _v2QueuedDrainScheduled = false;
|
|
813
825
|
let _v2QueuedEpoch = 0;
|
|
@@ -835,12 +847,69 @@ let _pendingMeshMessages = [];
|
|
|
835
847
|
let _agentRunActive = false;
|
|
836
848
|
let _agentRunGeneration = 0;
|
|
837
849
|
let _meshDrainScheduled = false;
|
|
850
|
+
function _queuedImageLimits() {
|
|
851
|
+
return _queuedImageLimitsForTest ?? {
|
|
852
|
+
perOwner: MAX_QUEUED_IMAGE_BYTES_PER_OWNER,
|
|
853
|
+
global: MAX_QUEUED_IMAGE_BYTES_GLOBAL,
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
/** Test-only: lower the image budget without allocating multi-megabyte frames. */
|
|
857
|
+
export function _setQueuedImageLimitsForTest(limits) {
|
|
858
|
+
if (limits && (!Number.isSafeInteger(limits.perOwner) || limits.perOwner < 0 ||
|
|
859
|
+
!Number.isSafeInteger(limits.global) || limits.global < 0)) {
|
|
860
|
+
throw new Error("queued image limits must be non-negative safe integers");
|
|
861
|
+
}
|
|
862
|
+
_queuedImageLimitsForTest = limits ? { ...limits } : null;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Count the retained wire representation, never decoded bytes. Base64 is ASCII
|
|
866
|
+
* under the strict v2 schema, and UTF-8 remains a conservative estimate for
|
|
867
|
+
* legacy input; this is stable without decoding or retaining a second buffer.
|
|
868
|
+
*/
|
|
869
|
+
function _estimateQueuedImageBytes(images) {
|
|
870
|
+
if (!images || images.length === 0)
|
|
871
|
+
return 0;
|
|
872
|
+
return images.reduce((total, image) => total + Buffer.byteLength(image.data, "utf8") + Buffer.byteLength(image.mime, "utf8"), 0);
|
|
873
|
+
}
|
|
874
|
+
function _reserveQueuedImageBytes(ownerRef, imageBytes) {
|
|
875
|
+
if (imageBytes === 0)
|
|
876
|
+
return true;
|
|
877
|
+
const limits = _queuedImageLimits();
|
|
878
|
+
const ownerBytes = _queuedImageBytesByOwner.get(ownerRef) ?? 0;
|
|
879
|
+
if (ownerBytes + imageBytes > limits.perOwner || _queuedImageBytesGlobal + imageBytes > limits.global) {
|
|
880
|
+
return false;
|
|
881
|
+
}
|
|
882
|
+
_queuedImageBytesGlobal += imageBytes;
|
|
883
|
+
_queuedImageBytesByOwner.set(ownerRef, ownerBytes + imageBytes);
|
|
884
|
+
return true;
|
|
885
|
+
}
|
|
886
|
+
function _releaseQueuedImageBytes(ownerRef, imageBytes) {
|
|
887
|
+
if (imageBytes === 0)
|
|
888
|
+
return;
|
|
889
|
+
const ownerBytes = _queuedImageBytesByOwner.get(ownerRef) ?? 0;
|
|
890
|
+
const remainingOwnerBytes = Math.max(0, ownerBytes - imageBytes);
|
|
891
|
+
if (remainingOwnerBytes === 0)
|
|
892
|
+
_queuedImageBytesByOwner.delete(ownerRef);
|
|
893
|
+
else
|
|
894
|
+
_queuedImageBytesByOwner.set(ownerRef, remainingOwnerBytes);
|
|
895
|
+
_queuedImageBytesGlobal = Math.max(0, _queuedImageBytesGlobal - imageBytes);
|
|
896
|
+
}
|
|
897
|
+
function _restoreQueuedImageBytes(ownerRef, imageBytes) {
|
|
898
|
+
if (imageBytes === 0)
|
|
899
|
+
return;
|
|
900
|
+
_queuedImageBytesGlobal += imageBytes;
|
|
901
|
+
_queuedImageBytesByOwner.set(ownerRef, (_queuedImageBytesByOwner.get(ownerRef) ?? 0) + imageBytes);
|
|
902
|
+
}
|
|
903
|
+
function _queuedStateItem(item) {
|
|
904
|
+
const { ownerRef, imageBytes: _imageBytes, ...wireItem } = item;
|
|
905
|
+
return { ...wireItem, sender_ref: ownerRef };
|
|
906
|
+
}
|
|
838
907
|
function _queuedStateMessage() {
|
|
839
908
|
const first = _queuedItems[0];
|
|
840
909
|
return {
|
|
841
910
|
type: "queued_message_state",
|
|
842
911
|
...(first ? { id: first.id, text: first.text } : {}),
|
|
843
|
-
items: _queuedItems.map(
|
|
912
|
+
items: _queuedItems.map(_queuedStateItem),
|
|
844
913
|
};
|
|
845
914
|
}
|
|
846
915
|
function _sendQueuedState(sender) {
|
|
@@ -850,28 +919,36 @@ function _broadcastQueuedState() {
|
|
|
850
919
|
_broadcastToActive(_queuedStateMessage());
|
|
851
920
|
}
|
|
852
921
|
function _resetQueuedItems({ broadcast = false } = {}) {
|
|
922
|
+
for (const item of _queuedItems)
|
|
923
|
+
_releaseQueuedImageBytes(item.ownerRef, item.imageBytes);
|
|
853
924
|
_queuedItems = [];
|
|
854
925
|
if (broadcast)
|
|
855
926
|
_broadcastQueuedState();
|
|
856
927
|
}
|
|
857
|
-
function
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
_queuedItems = [
|
|
864
|
-
..._queuedItems.slice(0, index),
|
|
865
|
-
item,
|
|
866
|
-
..._queuedItems.slice(index + 1),
|
|
867
|
-
];
|
|
928
|
+
function _enqueuePwaQueuedItem(item) {
|
|
929
|
+
if (_queuedItems.some((existing) => existing.id === item.id)) {
|
|
930
|
+
// Image attachments are immutable while queued. A retry is free; changing
|
|
931
|
+
// the item requires queued_message_clear followed by a new id.
|
|
932
|
+
_broadcastQueuedState();
|
|
933
|
+
return true;
|
|
868
934
|
}
|
|
935
|
+
if (!_reserveQueuedImageBytes(item.ownerRef, item.imageBytes))
|
|
936
|
+
return false;
|
|
937
|
+
_queuedItems = [..._queuedItems, item];
|
|
869
938
|
_broadcastQueuedState();
|
|
939
|
+
return true;
|
|
870
940
|
}
|
|
871
941
|
function _clearQueuedItems(targetId) {
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
942
|
+
const retained = [];
|
|
943
|
+
for (const item of _queuedItems) {
|
|
944
|
+
if (targetId === undefined || item.id === targetId) {
|
|
945
|
+
_releaseQueuedImageBytes(item.ownerRef, item.imageBytes);
|
|
946
|
+
}
|
|
947
|
+
else {
|
|
948
|
+
retained.push(item);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
_queuedItems = retained;
|
|
875
952
|
_broadcastQueuedState();
|
|
876
953
|
}
|
|
877
954
|
function _isBusyForQueueDrain() {
|
|
@@ -912,13 +989,20 @@ function _maybeDrainQueuedItem() {
|
|
|
912
989
|
const item = _queuedItems.shift();
|
|
913
990
|
if (!item)
|
|
914
991
|
return;
|
|
992
|
+
_releaseQueuedImageBytes(item.ownerRef, item.imageBytes);
|
|
915
993
|
_broadcastQueuedState();
|
|
916
994
|
const previousTurnId = _currentTurnId;
|
|
917
995
|
_currentTurnId = item.id;
|
|
918
|
-
const msg = {
|
|
919
|
-
|
|
996
|
+
const msg = {
|
|
997
|
+
type: "user_message",
|
|
998
|
+
id: item.id,
|
|
999
|
+
text: item.text,
|
|
1000
|
+
...(item.images && item.images.length > 0 ? { images: item.images } : {}),
|
|
1001
|
+
};
|
|
1002
|
+
const wake = _wakeAgent(_v2UserContent(item), `queued PWA user_message id=${item.id}`, "steer");
|
|
920
1003
|
if (!wake.ok) {
|
|
921
1004
|
_currentTurnId = previousTurnId;
|
|
1005
|
+
_restoreQueuedImageBytes(item.ownerRef, item.imageBytes);
|
|
922
1006
|
_queuedItems = [item, ..._queuedItems];
|
|
923
1007
|
_broadcastQueuedState();
|
|
924
1008
|
_broadcastToActive({
|
|
@@ -940,12 +1024,97 @@ function _v2UserContent(frame) {
|
|
|
940
1024
|
: frame.text;
|
|
941
1025
|
}
|
|
942
1026
|
function _resetV2QueuedUserMessages() {
|
|
1027
|
+
for (const item of _v2QueuedUserMessages)
|
|
1028
|
+
_releaseQueuedImageBytes(item.senderRef, item.imageBytes);
|
|
943
1029
|
_v2QueuedUserMessages = [];
|
|
944
1030
|
_v2QueuedDrainScheduled = false;
|
|
945
1031
|
_v2QueuedEpoch += 1;
|
|
1032
|
+
_broadcastV2QueuedState();
|
|
946
1033
|
}
|
|
947
1034
|
function _v2QueuedPayloadFingerprint(frame) {
|
|
948
|
-
return
|
|
1035
|
+
return fingerprintV2Payload({
|
|
1036
|
+
text: frame.text,
|
|
1037
|
+
images: frame.images ?? [],
|
|
1038
|
+
streaming_behavior: frame.streaming_behavior ?? null,
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
function _v2QueuedWireItem(item) {
|
|
1042
|
+
return {
|
|
1043
|
+
id: item.frame.client_request_id,
|
|
1044
|
+
text: item.frame.text,
|
|
1045
|
+
...(item.frame.images && item.frame.images.length > 0 ? { images: item.frame.images } : {}),
|
|
1046
|
+
sender_ref: item.senderRef,
|
|
1047
|
+
editable: true,
|
|
1048
|
+
created_at: item.enqueuedAt,
|
|
1049
|
+
};
|
|
1050
|
+
}
|
|
1051
|
+
function _v2QueuedItemFitsFrame(item, service) {
|
|
1052
|
+
return Buffer.byteLength(JSON.stringify({
|
|
1053
|
+
protocol_version: 2,
|
|
1054
|
+
type: "queued_message_state",
|
|
1055
|
+
session_id: _currentSessionManager?.getSessionId() ?? "unknown",
|
|
1056
|
+
history_generation: service.generation,
|
|
1057
|
+
snapshot_id: randomUUID(),
|
|
1058
|
+
chunk_index: 0,
|
|
1059
|
+
final: true,
|
|
1060
|
+
items: [_v2QueuedWireItem(item)],
|
|
1061
|
+
}), "utf8") <= MAX_FRAME_BYTES;
|
|
1062
|
+
}
|
|
1063
|
+
function _v2QueuedStateFrames(service) {
|
|
1064
|
+
const snapshotId = randomUUID();
|
|
1065
|
+
const items = _v2QueuedUserMessages.map((item) => _v2QueuedWireItem(item));
|
|
1066
|
+
const chunks = [];
|
|
1067
|
+
let current = [];
|
|
1068
|
+
for (const item of items) {
|
|
1069
|
+
const candidate = [...current, item];
|
|
1070
|
+
const probe = {
|
|
1071
|
+
protocol_version: 2,
|
|
1072
|
+
type: "queued_message_state",
|
|
1073
|
+
session_id: _currentSessionManager?.getSessionId() ?? "unknown",
|
|
1074
|
+
history_generation: service.generation,
|
|
1075
|
+
snapshot_id: snapshotId,
|
|
1076
|
+
chunk_index: chunks.length,
|
|
1077
|
+
final: false,
|
|
1078
|
+
items: candidate,
|
|
1079
|
+
};
|
|
1080
|
+
if (current.length > 0 && Buffer.byteLength(JSON.stringify(probe), "utf8") > MAX_FRAME_BYTES) {
|
|
1081
|
+
chunks.push(current);
|
|
1082
|
+
current = [item];
|
|
1083
|
+
}
|
|
1084
|
+
else {
|
|
1085
|
+
current = candidate;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
if (current.length > 0 || chunks.length === 0)
|
|
1089
|
+
chunks.push(current);
|
|
1090
|
+
return chunks.map((itemsChunk, index) => ({
|
|
1091
|
+
protocol_version: 2,
|
|
1092
|
+
type: "queued_message_state",
|
|
1093
|
+
session_id: _currentSessionManager?.getSessionId() ?? "unknown",
|
|
1094
|
+
history_generation: service.generation,
|
|
1095
|
+
snapshot_id: snapshotId,
|
|
1096
|
+
chunk_index: index,
|
|
1097
|
+
final: index === chunks.length - 1,
|
|
1098
|
+
items: itemsChunk,
|
|
1099
|
+
}));
|
|
1100
|
+
}
|
|
1101
|
+
function _broadcastV2QueuedState() {
|
|
1102
|
+
_broadcastV2((service) => _v2QueuedStateFrames(service));
|
|
1103
|
+
}
|
|
1104
|
+
function _clearV2QueuedUserMessages(senderRef, targetId) {
|
|
1105
|
+
const retained = [];
|
|
1106
|
+
for (const item of _v2QueuedUserMessages) {
|
|
1107
|
+
const matchesOwner = item.senderRef === senderRef;
|
|
1108
|
+
const matchesTarget = targetId === undefined || item.frame.client_request_id === targetId;
|
|
1109
|
+
if (matchesOwner && matchesTarget) {
|
|
1110
|
+
_releaseQueuedImageBytes(item.senderRef, item.imageBytes);
|
|
1111
|
+
}
|
|
1112
|
+
else {
|
|
1113
|
+
retained.push(item);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
_v2QueuedUserMessages = retained;
|
|
1117
|
+
_broadcastV2QueuedState();
|
|
949
1118
|
}
|
|
950
1119
|
function _sendV2QueuedUnknown(item, binding) {
|
|
951
1120
|
const serviceFrames = binding.service.unknownDelivery(item.frame.client_request_id);
|
|
@@ -962,17 +1131,22 @@ function _sendV2QueuedUnknown(item, binding) {
|
|
|
962
1131
|
}
|
|
963
1132
|
function _expireV2QueuedUserMessages(now) {
|
|
964
1133
|
const live = [];
|
|
1134
|
+
let changed = false;
|
|
965
1135
|
for (const item of _v2QueuedUserMessages) {
|
|
966
1136
|
if (now - item.enqueuedAt <= V2_QUEUED_USER_TTL_MS) {
|
|
967
1137
|
live.push(item);
|
|
968
1138
|
continue;
|
|
969
1139
|
}
|
|
1140
|
+
changed = true;
|
|
1141
|
+
_releaseQueuedImageBytes(item.senderRef, item.imageBytes);
|
|
970
1142
|
const binding = _v2ActivePeers.get(item.senderRef);
|
|
971
1143
|
if (binding && item.frame.history_generation === binding.service.generation) {
|
|
972
1144
|
_sendV2QueuedUnknown(item, binding);
|
|
973
1145
|
}
|
|
974
1146
|
}
|
|
975
1147
|
_v2QueuedUserMessages = live;
|
|
1148
|
+
if (changed)
|
|
1149
|
+
_broadcastV2QueuedState();
|
|
976
1150
|
}
|
|
977
1151
|
function _enqueueV2UserMessage(senderRef, frame, correlation) {
|
|
978
1152
|
const now = Date.now();
|
|
@@ -983,15 +1157,24 @@ function _enqueueV2UserMessage(senderRef, frame, correlation) {
|
|
|
983
1157
|
return duplicate.payloadFingerprint === payloadFingerprint;
|
|
984
1158
|
const ownerCount = _v2QueuedUserMessages.filter((item) => item.senderRef === senderRef).length;
|
|
985
1159
|
if (ownerCount >= MAX_V2_QUEUED_USERS_PER_OWNER || _v2QueuedUserMessages.length >= MAX_V2_QUEUED_USERS) {
|
|
986
|
-
return false;
|
|
987
|
-
}
|
|
1160
|
+
return frame.images && frame.images.length > 0 ? "rejected" : false;
|
|
1161
|
+
}
|
|
1162
|
+
const imageBytes = _estimateQueuedImageBytes(frame.images);
|
|
1163
|
+
const service = _v2ActivePeers.get(senderRef)?.service;
|
|
1164
|
+
const candidate = { senderRef, frame, enqueuedAt: now };
|
|
1165
|
+
if (imageBytes > 0 && (!service || !_v2QueuedItemFitsFrame(candidate, service)))
|
|
1166
|
+
return "rejected";
|
|
1167
|
+
if (!_reserveQueuedImageBytes(senderRef, imageBytes))
|
|
1168
|
+
return "rejected";
|
|
988
1169
|
_v2QueuedUserMessages.push({
|
|
989
1170
|
senderRef,
|
|
990
1171
|
frame,
|
|
991
1172
|
correlation: { ...correlation, delivery: "queued" },
|
|
992
1173
|
enqueuedAt: now,
|
|
1174
|
+
imageBytes,
|
|
993
1175
|
payloadFingerprint,
|
|
994
1176
|
});
|
|
1177
|
+
_broadcastV2QueuedState();
|
|
995
1178
|
return true;
|
|
996
1179
|
}
|
|
997
1180
|
function _scheduleV2QueuedUserDrain() {
|
|
@@ -1012,6 +1195,8 @@ function _scheduleV2QueuedUserDrain() {
|
|
|
1012
1195
|
const item = _v2QueuedUserMessages.shift();
|
|
1013
1196
|
if (!item)
|
|
1014
1197
|
return;
|
|
1198
|
+
_releaseQueuedImageBytes(item.senderRef, item.imageBytes);
|
|
1199
|
+
_broadcastV2QueuedState();
|
|
1015
1200
|
const binding = _v2ActivePeers.get(item.senderRef);
|
|
1016
1201
|
if (!binding || item.frame.history_generation !== binding.service.generation) {
|
|
1017
1202
|
_scheduleV2QueuedUserDrain();
|
|
@@ -1293,7 +1478,15 @@ function _detachPeerChannel(appPeerId) {
|
|
|
1293
1478
|
catch { /* best-effort */ }
|
|
1294
1479
|
_activePeers.delete(appPeerId);
|
|
1295
1480
|
_v2ActivePeers.delete(appPeerId);
|
|
1296
|
-
|
|
1481
|
+
const retainedV2QueuedItems = [];
|
|
1482
|
+
for (const item of _v2QueuedUserMessages) {
|
|
1483
|
+
if (item.senderRef === appPeerId)
|
|
1484
|
+
_releaseQueuedImageBytes(item.senderRef, item.imageBytes);
|
|
1485
|
+
else
|
|
1486
|
+
retainedV2QueuedItems.push(item);
|
|
1487
|
+
}
|
|
1488
|
+
_v2QueuedUserMessages = retainedV2QueuedItems;
|
|
1489
|
+
_broadcastV2QueuedState();
|
|
1297
1490
|
if (_peerShort === appPeerId.slice(0, 8)) {
|
|
1298
1491
|
// Pick a different remaining peer for the UX hint, or clear when none.
|
|
1299
1492
|
const next = _activePeers.keys().next().value ?? _v2ActivePeers.keys().next().value;
|
|
@@ -2521,7 +2714,9 @@ const extension = (pi) => {
|
|
|
2521
2714
|
// up exactly ONE connection bound to the restored session. Idempotent +
|
|
2522
2715
|
// best-effort: every step is guarded so a partially-initialised instance
|
|
2523
2716
|
// (e.g. shutdown lands mid-`_cmdRoot`) tears down without throwing.
|
|
2524
|
-
pi.on("session_shutdown", async () => {
|
|
2717
|
+
pi.on("session_shutdown", async (event) => {
|
|
2718
|
+
// Session replacement needs a fresh v2 handshake; process exit is final.
|
|
2719
|
+
const byeReason = event.reason === "quit" ? "shutdown" : "session_replaced";
|
|
2525
2720
|
// Revoke async authority synchronously, before any teardown await. `_disposed`
|
|
2526
2721
|
// blocks the outgoing continuation immediately; the root and candidate
|
|
2527
2722
|
// generations keep queued work stale even if a same-module session_start
|
|
@@ -2542,12 +2737,11 @@ const extension = (pi) => {
|
|
|
2542
2737
|
// (issue #55). session_start re-binds `_lastEventCtx` for the new session.
|
|
2543
2738
|
_lastCtx = null;
|
|
2544
2739
|
_lastEventCtx = null;
|
|
2545
|
-
//
|
|
2546
|
-
// the SAME relay room, so an explicit offline→online flap would be wrong.
|
|
2740
|
+
// Send bye before detaching its channel or closing the shared relay room.
|
|
2547
2741
|
// Revoke producer/Relay/bridge authority while the global node is still
|
|
2548
2742
|
// visible, before close() can begin its asynchronous UDS leave.
|
|
2549
2743
|
if (_state !== "idle") {
|
|
2550
|
-
_goIdle();
|
|
2744
|
+
_goIdle(byeReason);
|
|
2551
2745
|
}
|
|
2552
2746
|
else {
|
|
2553
2747
|
_meshNode?.detachBridge();
|
|
@@ -3402,7 +3596,7 @@ async function _cmdRevoke(arg, ctx) {
|
|
|
3402
3596
|
const legacyChannel = _activePeers.get(peer.runtimeKey);
|
|
3403
3597
|
const v2Binding = _v2ActivePeers.get(peer.runtimeKey);
|
|
3404
3598
|
try {
|
|
3405
|
-
legacyChannel?.send({ type: "bye", reason: "
|
|
3599
|
+
legacyChannel?.send({ type: "bye", reason: "peer_stop" });
|
|
3406
3600
|
}
|
|
3407
3601
|
catch { /* best-effort */ }
|
|
3408
3602
|
try {
|
|
@@ -3411,7 +3605,7 @@ async function _cmdRevoke(arg, ctx) {
|
|
|
3411
3605
|
type: "bye",
|
|
3412
3606
|
session_id: _currentSessionManager?.getSessionId() ?? "unknown",
|
|
3413
3607
|
history_generation: v2Binding.service.generation,
|
|
3414
|
-
reason: "
|
|
3608
|
+
reason: "peer_stop",
|
|
3415
3609
|
});
|
|
3416
3610
|
}
|
|
3417
3611
|
catch { /* best-effort */ }
|
|
@@ -4413,11 +4607,29 @@ export function _routeClientMessageFrom(sender, msg, ctx) {
|
|
|
4413
4607
|
switch (msg.type) {
|
|
4414
4608
|
case "queued_message_set": {
|
|
4415
4609
|
const text = msg.text.trim();
|
|
4416
|
-
|
|
4610
|
+
const images = msg.images && msg.images.length > 0 ? msg.images : undefined;
|
|
4611
|
+
if (!text && !images) {
|
|
4417
4612
|
_clearQueuedItems(msg.id);
|
|
4418
4613
|
break;
|
|
4419
4614
|
}
|
|
4420
|
-
|
|
4615
|
+
const queued = _enqueuePwaQueuedItem({
|
|
4616
|
+
id: msg.id,
|
|
4617
|
+
text,
|
|
4618
|
+
...(images ? { images } : {}),
|
|
4619
|
+
editable: true,
|
|
4620
|
+
created_at: Date.now(),
|
|
4621
|
+
ownerRef: sender.getPeerId(),
|
|
4622
|
+
imageBytes: _estimateQueuedImageBytes(images),
|
|
4623
|
+
});
|
|
4624
|
+
if (!queued) {
|
|
4625
|
+
sender.send({
|
|
4626
|
+
type: "error",
|
|
4627
|
+
code: "too_large",
|
|
4628
|
+
in_reply_to: msg.id,
|
|
4629
|
+
message: "Image queue capacity exceeded; retry after queued work drains.",
|
|
4630
|
+
});
|
|
4631
|
+
break;
|
|
4632
|
+
}
|
|
4421
4633
|
_maybeDrainQueuedItem();
|
|
4422
4634
|
break;
|
|
4423
4635
|
}
|