@forgeax/engine-intelligence 0.1.7 → 0.1.20

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/src/transport.ts CHANGED
@@ -71,7 +71,14 @@ export function bindIntelligencePort(
71
71
  return;
72
72
  }
73
73
  if (message.kind === 'intelligence-poll') {
74
- port.postMessage({ kind: 'intelligence-events', events: runtime.poll(message.maxEvents) });
74
+ const events = runtime.poll(message.maxEvents);
75
+ try {
76
+ port.postMessage({ kind: 'intelligence-events', events });
77
+ } catch {
78
+ // Poll is destructive; a failed response must terminate the Host binding
79
+ // so the drained events cannot remain attached to a live runtime.
80
+ void close().catch(() => undefined);
81
+ }
75
82
  return;
76
83
  }
77
84
  if (message.kind === 'intelligence-cancel') {
@@ -86,8 +93,13 @@ export function bindIntelligencePort(
86
93
  port.removeEventListener('message', listener);
87
94
  closeTask = (async () => {
88
95
  await runtime.close();
89
- port.postMessage({ kind: 'intelligence-closed' });
90
- setTimeout(() => port.close(), 0);
96
+ try {
97
+ port.postMessage({ kind: 'intelligence-closed' });
98
+ } catch {
99
+ // A failed terminal notification must not strand the physical transport.
100
+ }
101
+ await new Promise<void>((resolve) => setTimeout(resolve, 0));
102
+ port.close();
91
103
  })();
92
104
  return closeTask;
93
105
  };
@@ -146,6 +158,7 @@ export class IntelligencePortClient implements IntelligenceService {
146
158
  private pollPending = false;
147
159
  private closeTask: Promise<void> | undefined;
148
160
  private closeResolve: (() => void) | undefined;
161
+ private transportReleased = false;
149
162
 
150
163
  constructor(
151
164
  readonly providerId: string,
@@ -170,8 +183,7 @@ export class IntelligencePortClient implements IntelligenceService {
170
183
  this.rejected.set(message.activityId, message);
171
184
  } else if (message.kind === 'intelligence-closed') {
172
185
  this.markClosed();
173
- this.port.removeEventListener('message', this.listener);
174
- this.port.close();
186
+ this.releaseTransport();
175
187
  this.closeResolve?.();
176
188
  this.closeResolve = undefined;
177
189
  this.closeTask ??= Promise.resolve();
@@ -189,6 +201,13 @@ export class IntelligencePortClient implements IntelligenceService {
189
201
  this.pollPending = false;
190
202
  }
191
203
 
204
+ private releaseTransport(): void {
205
+ if (this.transportReleased) return;
206
+ this.transportReleased = true;
207
+ this.port.removeEventListener('message', this.listener);
208
+ this.port.close();
209
+ }
210
+
192
211
  submit(request: ActivityRequest): Result<ActivityRef, IntelligenceError> {
193
212
  if (this.closed) return err(new IntelligenceError({ code: 'intelligence-closed', detail: {} }));
194
213
  if (request.input.length === 0 || request.input.length > this.limits.maxInputChars) {
@@ -229,10 +248,16 @@ export class IntelligencePortClient implements IntelligenceService {
229
248
  session: request.session ?? { providerId: this.providerId, id: this.createSessionId() },
230
249
  };
231
250
  this.active.add(ref.id);
232
- this.port.postMessage({
233
- kind: 'intelligence-submit',
234
- submission: { ...ref, input: request.input },
235
- });
251
+ try {
252
+ this.port.postMessage({
253
+ kind: 'intelligence-submit',
254
+ submission: { ...ref, input: request.input },
255
+ });
256
+ } catch {
257
+ this.markClosed();
258
+ this.releaseTransport();
259
+ return err(new IntelligenceError({ code: 'intelligence-closed', detail: {} }));
260
+ }
236
261
  return ok(ref);
237
262
  }
238
263
 
@@ -252,7 +277,13 @@ export class IntelligencePortClient implements IntelligenceService {
252
277
  }
253
278
  if (!this.pollPending) {
254
279
  this.pollPending = true;
255
- this.port.postMessage({ kind: 'intelligence-poll', maxEvents: count });
280
+ try {
281
+ this.port.postMessage({ kind: 'intelligence-poll', maxEvents: count });
282
+ } catch {
283
+ this.markClosed();
284
+ this.releaseTransport();
285
+ return [];
286
+ }
256
287
  }
257
288
  return events;
258
289
  }
@@ -267,7 +298,13 @@ export class IntelligencePortClient implements IntelligenceService {
267
298
  }),
268
299
  );
269
300
  }
270
- this.port.postMessage({ kind: 'intelligence-cancel', activityId: id });
301
+ try {
302
+ this.port.postMessage({ kind: 'intelligence-cancel', activityId: id });
303
+ } catch {
304
+ this.markClosed();
305
+ this.releaseTransport();
306
+ return err(new IntelligenceError({ code: 'intelligence-closed', detail: {} }));
307
+ }
271
308
  return ok(undefined);
272
309
  }
273
310
 
@@ -280,7 +317,13 @@ export class IntelligencePortClient implements IntelligenceService {
280
317
  this.markClosed();
281
318
  this.closeTask = new Promise((resolve) => {
282
319
  this.closeResolve = resolve;
283
- this.port.postMessage({ kind: 'intelligence-close' });
320
+ try {
321
+ this.port.postMessage({ kind: 'intelligence-close' });
322
+ } catch {
323
+ this.releaseTransport();
324
+ this.closeResolve = undefined;
325
+ resolve();
326
+ }
284
327
  });
285
328
  return this.closeTask;
286
329
  }