@forgeax/engine-intelligence 0.1.6 → 0.1.7
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/README.md +17 -3
- package/dist/.tsbuildinfo +1 -1
- package/dist/index.mjs +48 -20
- package/dist/index.mjs.map +1 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/transport.d.ts +1 -0
- package/dist/transport.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/runtime.test.ts +711 -0
- package/src/__tests__/transport.test.ts +758 -0
- package/src/runtime.ts +26 -8
- package/src/transport.ts +25 -12
package/src/runtime.ts
CHANGED
|
@@ -108,7 +108,13 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
108
108
|
terminal: false,
|
|
109
109
|
};
|
|
110
110
|
this.records.set(submission.id, record);
|
|
111
|
-
|
|
111
|
+
let started: Result<void, IntelligenceError>;
|
|
112
|
+
try {
|
|
113
|
+
started = this.provider.start(submission, this.createSink(record));
|
|
114
|
+
} catch (cause) {
|
|
115
|
+
this.records.delete(submission.id);
|
|
116
|
+
return err(providerError(this.providerId, cause));
|
|
117
|
+
}
|
|
112
118
|
if (!started.ok) {
|
|
113
119
|
this.records.delete(submission.id);
|
|
114
120
|
return started;
|
|
@@ -142,7 +148,11 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
142
148
|
}),
|
|
143
149
|
);
|
|
144
150
|
}
|
|
145
|
-
|
|
151
|
+
try {
|
|
152
|
+
return this.provider.cancel(activity);
|
|
153
|
+
} catch (cause) {
|
|
154
|
+
return err(providerError(this.providerId, cause));
|
|
155
|
+
}
|
|
146
156
|
}
|
|
147
157
|
|
|
148
158
|
close(): Promise<void> {
|
|
@@ -152,7 +162,11 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
152
162
|
|
|
153
163
|
private async performClose(): Promise<void> {
|
|
154
164
|
this.closed = true;
|
|
155
|
-
|
|
165
|
+
try {
|
|
166
|
+
await this.provider.close();
|
|
167
|
+
} catch {
|
|
168
|
+
// Disposal is terminal; provider failure must not strand the realm transport.
|
|
169
|
+
}
|
|
156
170
|
this.records.clear();
|
|
157
171
|
}
|
|
158
172
|
|
|
@@ -195,7 +209,7 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
195
209
|
private createSink(record: ActivityRecord): ActivitySink {
|
|
196
210
|
return {
|
|
197
211
|
text: (text) => {
|
|
198
|
-
if (record.terminal || text.length === 0) return;
|
|
212
|
+
if (this.closed || record.terminal || text.length === 0) return;
|
|
199
213
|
if (record.outputChars + text.length > this.limits.maxOutputChars) {
|
|
200
214
|
this.overflow(record, 'output-chars', this.limits.maxOutputChars);
|
|
201
215
|
return;
|
|
@@ -208,7 +222,7 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
208
222
|
this.push(record, { type: 'text-delta', text });
|
|
209
223
|
},
|
|
210
224
|
complete: (output) => {
|
|
211
|
-
if (record.terminal) return;
|
|
225
|
+
if (this.closed || record.terminal) return;
|
|
212
226
|
if (output.length > this.limits.maxOutputChars) {
|
|
213
227
|
this.overflow(record, 'output-chars', this.limits.maxOutputChars);
|
|
214
228
|
return;
|
|
@@ -217,13 +231,13 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
217
231
|
this.push(record, { type: 'completed', session: record.ref.session, output });
|
|
218
232
|
},
|
|
219
233
|
fail: (cause) => {
|
|
220
|
-
if (record.terminal) return;
|
|
234
|
+
if (this.closed || record.terminal) return;
|
|
221
235
|
record.terminal = true;
|
|
222
236
|
const error = providerError(this.providerId, cause);
|
|
223
237
|
this.push(record, { type: 'failed', error: intelligenceFailure(error) });
|
|
224
238
|
},
|
|
225
239
|
cancelled: () => {
|
|
226
|
-
if (record.terminal) return;
|
|
240
|
+
if (this.closed || record.terminal) return;
|
|
227
241
|
record.terminal = true;
|
|
228
242
|
this.push(record, { type: 'cancelled' });
|
|
229
243
|
},
|
|
@@ -243,7 +257,11 @@ export class IntelligenceRuntime implements IntelligenceService {
|
|
|
243
257
|
});
|
|
244
258
|
if (record.events.length >= this.limits.maxPendingEventsPerActivity) record.events.pop();
|
|
245
259
|
this.push(record, { type: 'failed', error: intelligenceFailure(error) });
|
|
246
|
-
|
|
260
|
+
try {
|
|
261
|
+
this.provider.cancel(record.ref.id);
|
|
262
|
+
} catch {
|
|
263
|
+
// The overflow terminal already owns the activity outcome.
|
|
264
|
+
}
|
|
247
265
|
}
|
|
248
266
|
|
|
249
267
|
private push(
|
package/src/transport.ts
CHANGED
|
@@ -52,9 +52,11 @@ export function bindIntelligencePort(
|
|
|
52
52
|
runtime: IntelligenceRuntime,
|
|
53
53
|
): IntelligencePortBinding {
|
|
54
54
|
let closed = false;
|
|
55
|
+
let closeTask: Promise<void> | undefined;
|
|
55
56
|
const listener = (
|
|
56
57
|
event: MessageEvent<IntelligenceHostCommand | IntelligenceRealmMessage>,
|
|
57
58
|
): void => {
|
|
59
|
+
if (closed) return;
|
|
58
60
|
const message = event.data;
|
|
59
61
|
if (message.kind === 'intelligence-submit') {
|
|
60
62
|
const accepted = runtime.accept(message.submission);
|
|
@@ -76,19 +78,18 @@ export function bindIntelligencePort(
|
|
|
76
78
|
runtime.cancel(message.activityId);
|
|
77
79
|
return;
|
|
78
80
|
}
|
|
79
|
-
if (message.kind === 'intelligence-close') void close(
|
|
81
|
+
if (message.kind === 'intelligence-close') void close();
|
|
80
82
|
};
|
|
81
|
-
const close =
|
|
82
|
-
if (
|
|
83
|
+
const close = (): Promise<void> => {
|
|
84
|
+
if (closeTask !== undefined) return closeTask;
|
|
83
85
|
closed = true;
|
|
84
86
|
port.removeEventListener('message', listener);
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
closeTask = (async () => {
|
|
88
|
+
await runtime.close();
|
|
87
89
|
port.postMessage({ kind: 'intelligence-closed' });
|
|
88
90
|
setTimeout(() => port.close(), 0);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
}
|
|
91
|
+
})();
|
|
92
|
+
return closeTask;
|
|
92
93
|
};
|
|
93
94
|
port.addEventListener('message', listener);
|
|
94
95
|
port.start?.();
|
|
@@ -157,6 +158,7 @@ export class IntelligencePortClient implements IntelligenceService {
|
|
|
157
158
|
this.createSessionId = options.createSessionId ?? (() => nextPortIdentity('session'));
|
|
158
159
|
this.listener = (event) => {
|
|
159
160
|
const message = event.data;
|
|
161
|
+
if (this.closed && message.kind !== 'intelligence-closed') return;
|
|
160
162
|
if (message.kind === 'intelligence-events') {
|
|
161
163
|
this.pollPending = false;
|
|
162
164
|
for (const item of message.events) {
|
|
@@ -167,19 +169,26 @@ export class IntelligencePortClient implements IntelligenceService {
|
|
|
167
169
|
this.active.delete(message.activityId);
|
|
168
170
|
this.rejected.set(message.activityId, message);
|
|
169
171
|
} else if (message.kind === 'intelligence-closed') {
|
|
172
|
+
this.markClosed();
|
|
170
173
|
this.port.removeEventListener('message', this.listener);
|
|
171
|
-
this.received.length = 0;
|
|
172
|
-
this.active.clear();
|
|
173
|
-
this.rejected.clear();
|
|
174
174
|
this.port.close();
|
|
175
175
|
this.closeResolve?.();
|
|
176
176
|
this.closeResolve = undefined;
|
|
177
|
+
this.closeTask ??= Promise.resolve();
|
|
177
178
|
}
|
|
178
179
|
};
|
|
179
180
|
port.addEventListener('message', this.listener);
|
|
180
181
|
port.start?.();
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
private markClosed(): void {
|
|
185
|
+
this.closed = true;
|
|
186
|
+
this.received.length = 0;
|
|
187
|
+
this.active.clear();
|
|
188
|
+
this.rejected.clear();
|
|
189
|
+
this.pollPending = false;
|
|
190
|
+
}
|
|
191
|
+
|
|
183
192
|
submit(request: ActivityRequest): Result<ActivityRef, IntelligenceError> {
|
|
184
193
|
if (this.closed) return err(new IntelligenceError({ code: 'intelligence-closed', detail: {} }));
|
|
185
194
|
if (request.input.length === 0 || request.input.length > this.limits.maxInputChars) {
|
|
@@ -264,7 +273,11 @@ export class IntelligencePortClient implements IntelligenceService {
|
|
|
264
273
|
|
|
265
274
|
close(): Promise<void> {
|
|
266
275
|
if (this.closeTask !== undefined) return this.closeTask;
|
|
267
|
-
this.closed
|
|
276
|
+
if (this.closed) {
|
|
277
|
+
this.closeTask = Promise.resolve();
|
|
278
|
+
return this.closeTask;
|
|
279
|
+
}
|
|
280
|
+
this.markClosed();
|
|
268
281
|
this.closeTask = new Promise((resolve) => {
|
|
269
282
|
this.closeResolve = resolve;
|
|
270
283
|
this.port.postMessage({ kind: 'intelligence-close' });
|