fix(runtime): align AppServer conversation scope
This commit is contained in:
@@ -664,7 +664,7 @@ export class LineUpRuntime {
|
||||
v: 1,
|
||||
id: this.newID("msg"),
|
||||
type,
|
||||
conversation_id: this.requireConversationID(),
|
||||
conversation_id: this.wireConversationID(),
|
||||
sender: { kind: "human", id: this.session.uid },
|
||||
target: { kind: "agent", id: this.session.agent_uid },
|
||||
timestamp: this.now(),
|
||||
@@ -682,7 +682,7 @@ export class LineUpRuntime {
|
||||
v: 1,
|
||||
id: this.newID("msg"),
|
||||
type,
|
||||
conversation_id: this.requireConversationID(),
|
||||
conversation_id: this.wireConversationID(),
|
||||
sender: { kind: "human", id: this.session.uid },
|
||||
target: { kind: "agent", id: this.session.agent_uid },
|
||||
timestamp: this.now(),
|
||||
@@ -745,6 +745,15 @@ export class LineUpRuntime {
|
||||
|
||||
private processTransportMessage(message: TransportMessage): void {
|
||||
const payload = decodeTransportPayload(message.payload);
|
||||
// AppServer sync is channel-wide, so a channel can contain messages from
|
||||
// other users. They are not part of this Runtime's conversation and must
|
||||
// never reach scope routing or the Chat projection.
|
||||
if (message.from_uid !== this.session.uid
|
||||
&& message.from_uid !== this.session.agent_uid
|
||||
&& !message.from_uid.startsWith("agent_")) {
|
||||
runtimeLog("message.ignored", { stage: "sender" });
|
||||
return;
|
||||
}
|
||||
if (message.from_uid === this.session.uid) {
|
||||
const own = parseEnvelopeJSON(payload);
|
||||
if (own.ok && CONTROL_ECHO_TYPES.has(own.envelope.type)) return;
|
||||
@@ -754,7 +763,7 @@ export class LineUpRuntime {
|
||||
}
|
||||
|
||||
const scopeResolution = resolveIncomingScope(payload, {
|
||||
app_scope: "chat", conversation_id: this.requireConversationID(),
|
||||
app_scope: "chat", conversation_id: this.requireConversationID(), conversation_ids: [this.wireConversationID()],
|
||||
acceptsAppScope: scope => Boolean(this.apps.get(scope)?.enabled),
|
||||
});
|
||||
if (scopeResolution.disposition === "rejected") {
|
||||
@@ -762,7 +771,7 @@ export class LineUpRuntime {
|
||||
this.emit({ type: "scope-rejected", reason: scopeResolution.reason, raw: payload });
|
||||
return;
|
||||
}
|
||||
const route = this.toolRouter.route(payload, { app_scope: scopeResolution.scope.app_scope, conversation_id: this.requireConversationID(), inventory_revision: this.inventoryRevision });
|
||||
const route = this.toolRouter.route(payload, { app_scope: scopeResolution.scope.app_scope, conversation_id: this.requireConversationID(), conversation_ids: [this.wireConversationID()], inventory_revision: this.inventoryRevision });
|
||||
if (route.disposition === "rejected") {
|
||||
runtimeLog("tool.rejected", { reason: route.code });
|
||||
this.emit({ type: "scope-rejected", reason: route.code === "scope_mismatch" ? "scope_mismatch" : "invalid_scope", raw: payload });
|
||||
@@ -1072,6 +1081,12 @@ export class LineUpRuntime {
|
||||
if (!conversationID) throw new Error("LineUpRuntime has no active conversation.");
|
||||
return conversationID;
|
||||
}
|
||||
|
||||
/** AppServer's network conversation key; local persistence keeps Runtime's legacy key. */
|
||||
private wireConversationID(): string {
|
||||
if (!this.session.active) throw new Error("LineUpRuntime has no active conversation.");
|
||||
return `lineup:${this.session.channel_type}:${this.session.channel_id}:${this.session.uid}`;
|
||||
}
|
||||
}
|
||||
|
||||
function boundedFailure(value: string): string {
|
||||
|
||||
Reference in New Issue
Block a user