@modelprofile.com/flexharness 4.1.2 → 5.1.0
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/changelog.md +18 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexharness.d.ts +3 -0
- package/dist_ts/classes.flexharness.js +104 -36
- package/dist_ts/interfaces.d.ts +17 -8
- package/package.json +1 -1
- package/readme.hints.md +2 -1
- package/readme.md +46 -9
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +137 -27
- package/ts/interfaces.ts +20 -8
|
@@ -42,7 +42,7 @@ import type {
|
|
|
42
42
|
IFlexMessagePage,
|
|
43
43
|
IFlexMessagePageOptions,
|
|
44
44
|
IFlexModelIdentity,
|
|
45
|
-
|
|
45
|
+
IFlexPartSnapshotEvent,
|
|
46
46
|
IFlexPermissionRequest,
|
|
47
47
|
IFlexPermissionRequestInput,
|
|
48
48
|
IFlexPermissionSnapshot,
|
|
@@ -74,6 +74,7 @@ import type {
|
|
|
74
74
|
IFlexSchedulePromptOptions,
|
|
75
75
|
IFlexScopeSnapshot,
|
|
76
76
|
IFlexSession,
|
|
77
|
+
IFlexSessionGeneration,
|
|
77
78
|
IFlexSessionReversionGroup,
|
|
78
79
|
IFlexSessionReversionInfo,
|
|
79
80
|
IFlexSessionTombstone,
|
|
@@ -321,6 +322,7 @@ interface IActiveRun {
|
|
|
321
322
|
callbackEventCount: number;
|
|
322
323
|
callbackOutputBytes: number;
|
|
323
324
|
callbackParts: TFlexMessagePart[];
|
|
325
|
+
partTextUtf8Bytes: Map<string, number>;
|
|
324
326
|
callbacksClosed: boolean;
|
|
325
327
|
reasoningPartIds: Map<string, string>;
|
|
326
328
|
toolPartIds: Map<string, string>;
|
|
@@ -518,7 +520,7 @@ function requireSessionGeneration(
|
|
|
518
520
|
IFlexSession | IFlexSessionTombstone,
|
|
519
521
|
'sessionGenerationId' | 'sessionGenerationSequence'
|
|
520
522
|
>,
|
|
521
|
-
):
|
|
523
|
+
): IFlexSessionGeneration {
|
|
522
524
|
if (
|
|
523
525
|
!session.sessionGenerationId
|
|
524
526
|
|| !Number.isSafeInteger(session.sessionGenerationSequence)
|
|
@@ -1848,6 +1850,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
1848
1850
|
scope,
|
|
1849
1851
|
storageKey: state.storageKey,
|
|
1850
1852
|
sessionId: stored.session.sessionId,
|
|
1853
|
+
...requireSessionGeneration(stored.session),
|
|
1851
1854
|
rawArguments,
|
|
1852
1855
|
arguments: arguments_,
|
|
1853
1856
|
signal,
|
|
@@ -2511,6 +2514,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
2511
2514
|
): Promise<void> {
|
|
2512
2515
|
const pending = stored.pendingReversion;
|
|
2513
2516
|
if (pending?.kind !== 'apply') return;
|
|
2517
|
+
const sessionGeneration = requireSessionGeneration(stored.session);
|
|
2514
2518
|
const segmentMap = new Map(stored.reversionSegments.map((segment) => [segment.runId, segment]));
|
|
2515
2519
|
if (
|
|
2516
2520
|
pending.segmentRunIds.some((runId) =>
|
|
@@ -2551,6 +2555,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
2551
2555
|
scope,
|
|
2552
2556
|
storageKey: state.storageKey,
|
|
2553
2557
|
sessionId: stored.session.sessionId,
|
|
2558
|
+
...sessionGeneration,
|
|
2554
2559
|
runId,
|
|
2555
2560
|
captureId,
|
|
2556
2561
|
reference: cloneSerializable(reference),
|
|
@@ -2684,6 +2689,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
2684
2689
|
scopeId,
|
|
2685
2690
|
scope,
|
|
2686
2691
|
stored.session.sessionId,
|
|
2692
|
+
requireSessionGeneration(stored.session),
|
|
2687
2693
|
pending.runId,
|
|
2688
2694
|
pending.captureId,
|
|
2689
2695
|
pending.state === 'prepared' ? 'finalizing' : pending.state,
|
|
@@ -3110,6 +3116,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
3110
3116
|
callbackEventCount: 0,
|
|
3111
3117
|
callbackOutputBytes: 0,
|
|
3112
3118
|
callbackParts: [],
|
|
3119
|
+
partTextUtf8Bytes: new Map(),
|
|
3113
3120
|
callbacksClosed: false,
|
|
3114
3121
|
reasoningPartIds: new Map(),
|
|
3115
3122
|
toolPartIds: new Map(),
|
|
@@ -3997,6 +4004,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
3997
4004
|
scopeId: run.scopeId,
|
|
3998
4005
|
scope: run.scope as TScope,
|
|
3999
4006
|
sessionId: run.sessionId,
|
|
4007
|
+
...requireSessionGeneration(run.stored.session),
|
|
4000
4008
|
runId: run.runId,
|
|
4001
4009
|
...resolverRelationship,
|
|
4002
4010
|
signal,
|
|
@@ -4965,6 +4973,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
4965
4973
|
scope: run.scope as TScope,
|
|
4966
4974
|
storageKey: run.state.storageKey,
|
|
4967
4975
|
sessionId: run.sessionId,
|
|
4976
|
+
...requireSessionGeneration(run.stored.session),
|
|
4968
4977
|
runId: run.runId,
|
|
4969
4978
|
captureId,
|
|
4970
4979
|
signal,
|
|
@@ -4999,6 +5008,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
4999
5008
|
scope: TScope,
|
|
5000
5009
|
storageKey: string,
|
|
5001
5010
|
sessionId: string,
|
|
5011
|
+
sessionGeneration: Readonly<IFlexSessionGeneration>,
|
|
5002
5012
|
runId: string,
|
|
5003
5013
|
captureId: string,
|
|
5004
5014
|
): Promise<TNormalizedCaptureInspection> {
|
|
@@ -5009,6 +5019,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5009
5019
|
scope,
|
|
5010
5020
|
storageKey,
|
|
5011
5021
|
sessionId,
|
|
5022
|
+
...sessionGeneration,
|
|
5012
5023
|
runId,
|
|
5013
5024
|
captureId,
|
|
5014
5025
|
signal,
|
|
@@ -5042,6 +5053,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5042
5053
|
scope: TScope,
|
|
5043
5054
|
storageKey: string,
|
|
5044
5055
|
sessionId: string,
|
|
5056
|
+
sessionGeneration: Readonly<IFlexSessionGeneration>,
|
|
5045
5057
|
runId: string,
|
|
5046
5058
|
captureId: string,
|
|
5047
5059
|
): Promise<TFlexTurnReversionFinalizedOutcome> {
|
|
@@ -5051,6 +5063,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5051
5063
|
scope,
|
|
5052
5064
|
storageKey,
|
|
5053
5065
|
sessionId,
|
|
5066
|
+
...sessionGeneration,
|
|
5054
5067
|
runId,
|
|
5055
5068
|
captureId,
|
|
5056
5069
|
signal,
|
|
@@ -5070,6 +5083,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5070
5083
|
scopeId: string,
|
|
5071
5084
|
scope: TScope,
|
|
5072
5085
|
sessionId: string,
|
|
5086
|
+
sessionGeneration: Readonly<IFlexSessionGeneration>,
|
|
5073
5087
|
runId: string,
|
|
5074
5088
|
captureId: string,
|
|
5075
5089
|
durableState: 'preparing' | 'prepared' | 'finalizing',
|
|
@@ -5081,6 +5095,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5081
5095
|
scope,
|
|
5082
5096
|
state.storageKey,
|
|
5083
5097
|
sessionId,
|
|
5098
|
+
sessionGeneration,
|
|
5084
5099
|
runId,
|
|
5085
5100
|
captureId,
|
|
5086
5101
|
);
|
|
@@ -5105,6 +5120,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5105
5120
|
scope,
|
|
5106
5121
|
state.storageKey,
|
|
5107
5122
|
sessionId,
|
|
5123
|
+
sessionGeneration,
|
|
5108
5124
|
runId,
|
|
5109
5125
|
captureId,
|
|
5110
5126
|
);
|
|
@@ -5114,6 +5130,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5114
5130
|
scope,
|
|
5115
5131
|
state.storageKey,
|
|
5116
5132
|
sessionId,
|
|
5133
|
+
sessionGeneration,
|
|
5117
5134
|
runId,
|
|
5118
5135
|
captureId,
|
|
5119
5136
|
);
|
|
@@ -5266,6 +5283,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5266
5283
|
run.scope as TScope,
|
|
5267
5284
|
run.state.storageKey,
|
|
5268
5285
|
run.sessionId,
|
|
5286
|
+
requireSessionGeneration(run.stored.session),
|
|
5269
5287
|
run.runId,
|
|
5270
5288
|
captureId,
|
|
5271
5289
|
);
|
|
@@ -5347,6 +5365,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5347
5365
|
run.scopeId,
|
|
5348
5366
|
run.scope as TScope,
|
|
5349
5367
|
run.sessionId,
|
|
5368
|
+
requireSessionGeneration(run.stored.session),
|
|
5350
5369
|
run.runId,
|
|
5351
5370
|
captureId,
|
|
5352
5371
|
pending.state === 'prepared' ? 'finalizing' : pending.state,
|
|
@@ -5596,6 +5615,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5596
5615
|
}
|
|
5597
5616
|
return;
|
|
5598
5617
|
}
|
|
5618
|
+
const sessionGeneration = requireSessionGeneration(stored.session);
|
|
5599
5619
|
while (stored.pendingReversionReleases.length > 0) {
|
|
5600
5620
|
const release = stored.pendingReversionReleases[0];
|
|
5601
5621
|
if (this.reversionProviderProtocolVersion() !== release.protocolVersion) {
|
|
@@ -5610,6 +5630,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5610
5630
|
scope,
|
|
5611
5631
|
storageKey: state.storageKey,
|
|
5612
5632
|
sessionId: stored.session.sessionId,
|
|
5633
|
+
...sessionGeneration,
|
|
5613
5634
|
runId: release.runId,
|
|
5614
5635
|
captureId: release.captureId,
|
|
5615
5636
|
reference: cloneSerializable(release.reference),
|
|
@@ -5647,11 +5668,13 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5647
5668
|
private async releaseDeletedSessionReversions(
|
|
5648
5669
|
state: IStorageState,
|
|
5649
5670
|
storageKey: string,
|
|
5650
|
-
|
|
5671
|
+
tombstone: IFlexSessionTombstone,
|
|
5651
5672
|
scopeId: string,
|
|
5652
5673
|
scope: TScope,
|
|
5653
5674
|
stored?: IStoredSessionState,
|
|
5654
5675
|
): Promise<void> {
|
|
5676
|
+
const sessionId = tombstone.sessionId;
|
|
5677
|
+
const sessionGeneration = requireSessionGeneration(stored?.session ?? tombstone);
|
|
5655
5678
|
if (stored) await stored.projectionQueue;
|
|
5656
5679
|
let durableProjection = await this.stores.projections.load(storageKey, sessionId);
|
|
5657
5680
|
if (!durableProjection) return;
|
|
@@ -5710,6 +5733,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5710
5733
|
scope,
|
|
5711
5734
|
storageKey,
|
|
5712
5735
|
sessionId,
|
|
5736
|
+
...sessionGeneration,
|
|
5713
5737
|
runId,
|
|
5714
5738
|
captureId,
|
|
5715
5739
|
reference: cloneSerializable(reference),
|
|
@@ -5823,6 +5847,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5823
5847
|
scope,
|
|
5824
5848
|
storageKey,
|
|
5825
5849
|
sessionId,
|
|
5850
|
+
sessionGeneration,
|
|
5826
5851
|
capture.runId,
|
|
5827
5852
|
capture.captureId,
|
|
5828
5853
|
);
|
|
@@ -5852,6 +5877,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5852
5877
|
scope,
|
|
5853
5878
|
storageKey,
|
|
5854
5879
|
sessionId,
|
|
5880
|
+
sessionGeneration,
|
|
5855
5881
|
capture.runId,
|
|
5856
5882
|
capture.captureId,
|
|
5857
5883
|
);
|
|
@@ -5861,6 +5887,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5861
5887
|
scope,
|
|
5862
5888
|
storageKey,
|
|
5863
5889
|
sessionId,
|
|
5890
|
+
sessionGeneration,
|
|
5864
5891
|
capture.runId,
|
|
5865
5892
|
capture.captureId,
|
|
5866
5893
|
);
|
|
@@ -5926,6 +5953,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5926
5953
|
scope,
|
|
5927
5954
|
storageKey,
|
|
5928
5955
|
sessionId,
|
|
5956
|
+
...sessionGeneration,
|
|
5929
5957
|
runId: release.runId,
|
|
5930
5958
|
captureId: release.captureId,
|
|
5931
5959
|
reference: cloneSerializable(release.reference),
|
|
@@ -6062,14 +6090,25 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6062
6090
|
if (!run || !delta) return;
|
|
6063
6091
|
const lastPart = run.callbackParts.at(-1);
|
|
6064
6092
|
const created = lastPart?.type !== 'text';
|
|
6065
|
-
if (!this.reserveCallbackCapacity(run, created ? 2 : 1, Buffer.byteLength(delta), created ? 1 : 0)) return;
|
|
6066
6093
|
const part = lastPart?.type === 'text'
|
|
6067
6094
|
? lastPart
|
|
6068
6095
|
: { partId: plugins.crypto.randomUUID(), type: 'text' as const, text: '' };
|
|
6069
|
-
|
|
6096
|
+
const accounting = this.textAppendAccounting(run, part, delta, created);
|
|
6097
|
+
if (!accounting) return;
|
|
6098
|
+
if (!this.reserveCallbackCapacity(
|
|
6099
|
+
run,
|
|
6100
|
+
created ? 2 : 1,
|
|
6101
|
+
accounting.textUtf8Bytes - accounting.baseTextUtf8Bytes,
|
|
6102
|
+
created ? 1 : 0,
|
|
6103
|
+
)) return;
|
|
6104
|
+
if (created) {
|
|
6105
|
+
run.callbackParts.push(part);
|
|
6106
|
+
run.partTextUtf8Bytes.set(part.partId, 0);
|
|
6107
|
+
this.emitPartEvent(run, 'part.started', part);
|
|
6108
|
+
}
|
|
6070
6109
|
part.text += delta;
|
|
6071
|
-
|
|
6072
|
-
this.
|
|
6110
|
+
run.partTextUtf8Bytes.set(part.partId, accounting.textUtf8Bytes);
|
|
6111
|
+
this.emitPartDeltaEvent(run, part, delta, accounting);
|
|
6073
6112
|
}
|
|
6074
6113
|
|
|
6075
6114
|
private onReasoningStart(state: IStorageState, sessionId: string, id: string): void {
|
|
@@ -6084,6 +6123,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6084
6123
|
};
|
|
6085
6124
|
run.reasoningPartIds.set(id, part.partId);
|
|
6086
6125
|
run.callbackParts.push(part);
|
|
6126
|
+
run.partTextUtf8Bytes.set(part.partId, 0);
|
|
6087
6127
|
this.emitPartEvent(run, 'part.started', part);
|
|
6088
6128
|
}
|
|
6089
6129
|
|
|
@@ -6094,9 +6134,17 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6094
6134
|
const partId = run.reasoningPartIds.get(id);
|
|
6095
6135
|
const part = run.callbackParts.find((entry) => entry.partId === partId && entry.type === 'reasoning');
|
|
6096
6136
|
if (!part || part.type !== 'reasoning' || part.status !== 'running') return;
|
|
6097
|
-
|
|
6137
|
+
const accounting = this.textAppendAccounting(run, part, delta);
|
|
6138
|
+
if (!accounting) return;
|
|
6139
|
+
if (!this.reserveCallbackCapacity(
|
|
6140
|
+
run,
|
|
6141
|
+
1,
|
|
6142
|
+
accounting.textUtf8Bytes - accounting.baseTextUtf8Bytes,
|
|
6143
|
+
0,
|
|
6144
|
+
)) return;
|
|
6098
6145
|
part.text += delta;
|
|
6099
|
-
|
|
6146
|
+
run.partTextUtf8Bytes.set(part.partId, accounting.textUtf8Bytes);
|
|
6147
|
+
this.emitPartDeltaEvent(run, part, delta, accounting);
|
|
6100
6148
|
}
|
|
6101
6149
|
|
|
6102
6150
|
private onReasoningEnd(state: IStorageState, sessionId: string, id: string, text: string): void {
|
|
@@ -6107,12 +6155,44 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6107
6155
|
const part = run.callbackParts.find((entry) => entry.partId === partId && entry.type === 'reasoning');
|
|
6108
6156
|
if (!part || part.type !== 'reasoning' || part.status !== 'running') return;
|
|
6109
6157
|
const missingText = part.text ? '' : text;
|
|
6110
|
-
|
|
6111
|
-
if (
|
|
6158
|
+
const missingTextUtf8Bytes = Buffer.byteLength(missingText, 'utf8');
|
|
6159
|
+
if (!this.reserveCallbackCapacity(run, 1, missingTextUtf8Bytes, 0)) return;
|
|
6160
|
+
if (missingText) {
|
|
6161
|
+
part.text = missingText;
|
|
6162
|
+
run.partTextUtf8Bytes.set(part.partId, missingTextUtf8Bytes);
|
|
6163
|
+
}
|
|
6112
6164
|
part.status = 'completed';
|
|
6113
6165
|
this.emitPartEvent(run, 'part.completed', part);
|
|
6114
6166
|
}
|
|
6115
6167
|
|
|
6168
|
+
private textAppendAccounting(
|
|
6169
|
+
run: IActiveRun,
|
|
6170
|
+
part: Extract<TFlexMessagePart, { type: 'text' | 'reasoning' }>,
|
|
6171
|
+
delta: string,
|
|
6172
|
+
created = false,
|
|
6173
|
+
): { baseTextUtf8Bytes: number; textUtf8Bytes: number } | undefined {
|
|
6174
|
+
const baseTextUtf8Bytes = created ? 0 : run.partTextUtf8Bytes.get(part.partId);
|
|
6175
|
+
if (baseTextUtf8Bytes === undefined) {
|
|
6176
|
+
throw new Error('Flex part text byte accounting is unavailable.');
|
|
6177
|
+
}
|
|
6178
|
+
const trailingCodeUnit = part.text.charCodeAt(part.text.length - 1);
|
|
6179
|
+
const leadingCodeUnit = delta.charCodeAt(0);
|
|
6180
|
+
const joinsSurrogatePair = trailingCodeUnit >= 0xD800
|
|
6181
|
+
&& trailingCodeUnit <= 0xDBFF
|
|
6182
|
+
&& leadingCodeUnit >= 0xDC00
|
|
6183
|
+
&& leadingCodeUnit <= 0xDFFF;
|
|
6184
|
+
const textUtf8Bytes = baseTextUtf8Bytes
|
|
6185
|
+
+ Buffer.byteLength(delta, 'utf8')
|
|
6186
|
+
- (joinsSurrogatePair ? 2 : 0);
|
|
6187
|
+
if (!Number.isSafeInteger(textUtf8Bytes)) {
|
|
6188
|
+
this.failCallback(run, this.trustInternalError(new FlexHarnessCallbackOverflowError(
|
|
6189
|
+
'Callback text byte accounting exceeded the safe integer range.',
|
|
6190
|
+
)));
|
|
6191
|
+
return undefined;
|
|
6192
|
+
}
|
|
6193
|
+
return { baseTextUtf8Bytes, textUtf8Bytes };
|
|
6194
|
+
}
|
|
6195
|
+
|
|
6116
6196
|
private onToolStart(
|
|
6117
6197
|
state: IStorageState,
|
|
6118
6198
|
sessionId: string,
|
|
@@ -6211,7 +6291,10 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6211
6291
|
const nextOutputBytes = run.callbackOutputBytes + outputBytes;
|
|
6212
6292
|
const nextParts = run.callbackParts.length + partCount;
|
|
6213
6293
|
if (
|
|
6214
|
-
nextEvents
|
|
6294
|
+
!Number.isSafeInteger(nextEvents)
|
|
6295
|
+
|| !Number.isSafeInteger(nextOutputBytes)
|
|
6296
|
+
|| !Number.isSafeInteger(nextParts)
|
|
6297
|
+
|| nextEvents > this.callbackLimits.maxEvents
|
|
6215
6298
|
|| nextOutputBytes > this.callbackLimits.maxOutputBytes
|
|
6216
6299
|
|| nextParts > this.callbackLimits.maxParts
|
|
6217
6300
|
) {
|
|
@@ -6650,6 +6733,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6650
6733
|
scopeId: context.scopeId,
|
|
6651
6734
|
scope: context.scope,
|
|
6652
6735
|
sessionId: context.sessionId,
|
|
6736
|
+
...requireSessionGeneration(run.stored.session),
|
|
6653
6737
|
runId: context.runId,
|
|
6654
6738
|
...(context.parentSessionId === undefined ? {} : { parentSessionId: context.parentSessionId }),
|
|
6655
6739
|
...(context.agent === undefined ? {} : { agent: context.agent }),
|
|
@@ -7059,7 +7143,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
7059
7143
|
await this.releaseDeletedSessionReversions(
|
|
7060
7144
|
state,
|
|
7061
7145
|
storageKey,
|
|
7062
|
-
tombstone
|
|
7146
|
+
tombstone,
|
|
7063
7147
|
scopeId,
|
|
7064
7148
|
scope,
|
|
7065
7149
|
);
|
|
@@ -8305,7 +8389,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
8305
8389
|
await this.releaseDeletedSessionReversions(
|
|
8306
8390
|
state,
|
|
8307
8391
|
state.storageKey,
|
|
8308
|
-
|
|
8392
|
+
tombstone,
|
|
8309
8393
|
releaseContext.scopeId,
|
|
8310
8394
|
releaseContext.scope,
|
|
8311
8395
|
retained?.stored,
|
|
@@ -9329,20 +9413,10 @@ export class FlexHarness<TScope = unknown> {
|
|
|
9329
9413
|
|
|
9330
9414
|
private emitPartEvent(
|
|
9331
9415
|
run: IActiveRun,
|
|
9332
|
-
type:
|
|
9416
|
+
type: IFlexPartSnapshotEvent['type'],
|
|
9333
9417
|
part: TFlexMessagePart,
|
|
9334
|
-
delta?: string,
|
|
9335
9418
|
): void {
|
|
9336
|
-
const messageIndex = run.
|
|
9337
|
-
(message) => message.messageId === run.assistantMessageId,
|
|
9338
|
-
);
|
|
9339
|
-
const partIndex = run.callbackParts.findIndex((entry) => entry.partId === part.partId);
|
|
9340
|
-
if (
|
|
9341
|
-
messageIndex < 0
|
|
9342
|
-
|| run.stored.messages[messageIndex]?.messageId !== run.assistantMessageId
|
|
9343
|
-
|| partIndex < 0
|
|
9344
|
-
|| run.callbackParts[partIndex]?.partId !== part.partId
|
|
9345
|
-
) throw new Error('Flex part event source coordinates are unavailable.');
|
|
9419
|
+
const { messageIndex, partIndex } = this.partEventCoordinates(run, part.partId);
|
|
9346
9420
|
this.emitEvent(run.scopeId, run.sessionId, {
|
|
9347
9421
|
type,
|
|
9348
9422
|
runId: run.runId,
|
|
@@ -9351,10 +9425,46 @@ export class FlexHarness<TScope = unknown> {
|
|
|
9351
9425
|
partId: part.partId,
|
|
9352
9426
|
partIndex,
|
|
9353
9427
|
part: publicSnapshot(part),
|
|
9354
|
-
...(delta === undefined ? {} : { delta: truncateUtf8(delta, maxTransferTextBytes) }),
|
|
9355
9428
|
});
|
|
9356
9429
|
}
|
|
9357
9430
|
|
|
9431
|
+
private emitPartDeltaEvent(
|
|
9432
|
+
run: IActiveRun,
|
|
9433
|
+
part: Extract<TFlexMessagePart, { type: 'text' | 'reasoning' }>,
|
|
9434
|
+
delta: string,
|
|
9435
|
+
accounting: { baseTextUtf8Bytes: number; textUtf8Bytes: number },
|
|
9436
|
+
): void {
|
|
9437
|
+
const { messageIndex, partIndex } = this.partEventCoordinates(run, part.partId);
|
|
9438
|
+
this.emitEvent(run.scopeId, run.sessionId, {
|
|
9439
|
+
type: 'part.delta',
|
|
9440
|
+
runId: run.runId,
|
|
9441
|
+
messageId: run.assistantMessageId,
|
|
9442
|
+
messageIndex,
|
|
9443
|
+
partId: part.partId,
|
|
9444
|
+
partIndex,
|
|
9445
|
+
partType: part.type,
|
|
9446
|
+
delta,
|
|
9447
|
+
...accounting,
|
|
9448
|
+
});
|
|
9449
|
+
}
|
|
9450
|
+
|
|
9451
|
+
private partEventCoordinates(
|
|
9452
|
+
run: IActiveRun,
|
|
9453
|
+
partId: string,
|
|
9454
|
+
): { messageIndex: number; partIndex: number } {
|
|
9455
|
+
const messageIndex = run.stored.messages.findIndex(
|
|
9456
|
+
(message) => message.messageId === run.assistantMessageId,
|
|
9457
|
+
);
|
|
9458
|
+
const partIndex = run.callbackParts.findIndex((entry) => entry.partId === partId);
|
|
9459
|
+
if (
|
|
9460
|
+
messageIndex < 0
|
|
9461
|
+
|| run.stored.messages[messageIndex]?.messageId !== run.assistantMessageId
|
|
9462
|
+
|| partIndex < 0
|
|
9463
|
+
|| run.callbackParts[partIndex]?.partId !== partId
|
|
9464
|
+
) throw new Error('Flex part event source coordinates are unavailable.');
|
|
9465
|
+
return { messageIndex, partIndex };
|
|
9466
|
+
}
|
|
9467
|
+
|
|
9358
9468
|
private emitEvent(scopeId: string, sessionId: string, details: TEventDetails): void {
|
|
9359
9469
|
const event = deepFreeze(cloneSerializable({
|
|
9360
9470
|
eventId: plugins.crypto.randomUUID(),
|
package/ts/interfaces.ts
CHANGED
|
@@ -207,7 +207,7 @@ export interface IFlexSlashCommandDescriptor {
|
|
|
207
207
|
workspaceReversion: TFlexSlashCommandWorkspaceReversion;
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
export interface IFlexSlashCommandHandlerContext<TScope> {
|
|
210
|
+
export interface IFlexSlashCommandHandlerContext<TScope> extends IFlexSessionGeneration {
|
|
211
211
|
readonly scopeId: string;
|
|
212
212
|
readonly scope: TScope;
|
|
213
213
|
readonly storageKey: string;
|
|
@@ -386,7 +386,7 @@ export interface IFlexPermissionRequest extends IFlexPermissionRequestInput {
|
|
|
386
386
|
|
|
387
387
|
export type TFlexPermissionDecision = 'once' | 'always' | 'reject';
|
|
388
388
|
|
|
389
|
-
export interface IFlexToolProviderContext<TScope> {
|
|
389
|
+
export interface IFlexToolProviderContext<TScope> extends IFlexSessionGeneration {
|
|
390
390
|
scopeId: string;
|
|
391
391
|
scope: TScope;
|
|
392
392
|
sessionId: string;
|
|
@@ -408,7 +408,7 @@ export interface IFlexToolProvider<TScope> {
|
|
|
408
408
|
): Promise<IFlexToolHandle | undefined> | IFlexToolHandle | undefined;
|
|
409
409
|
}
|
|
410
410
|
|
|
411
|
-
export interface IFlexResourceToolProviderResolverContext<TScope> {
|
|
411
|
+
export interface IFlexResourceToolProviderResolverContext<TScope> extends IFlexSessionGeneration {
|
|
412
412
|
scopeId: string;
|
|
413
413
|
scope: TScope;
|
|
414
414
|
sessionId: string;
|
|
@@ -793,7 +793,7 @@ export const FLEX_REVERSION_WORKSPACE_ID_MAX_BYTES = 512;
|
|
|
793
793
|
export const FLEX_REVERSION_WORKSPACE_LABEL_MAX_BYTES = 2048;
|
|
794
794
|
export const FLEX_REVERSION_REASON_CODE_MAX_BYTES = 128;
|
|
795
795
|
|
|
796
|
-
export interface IFlexTurnReversionBaseContext<TScope> {
|
|
796
|
+
export interface IFlexTurnReversionBaseContext<TScope> extends IFlexSessionGeneration {
|
|
797
797
|
readonly scopeId: string;
|
|
798
798
|
readonly scope: TScope;
|
|
799
799
|
readonly storageKey: string;
|
|
@@ -1107,8 +1107,7 @@ export interface IFlexMessageChangedEvent extends IFlexEventBase {
|
|
|
1107
1107
|
readonly message: IFlexMessage;
|
|
1108
1108
|
}
|
|
1109
1109
|
|
|
1110
|
-
export interface
|
|
1111
|
-
readonly type: 'part.started' | 'part.delta' | 'part.updated' | 'part.completed';
|
|
1110
|
+
export interface IFlexPartEventBase extends IFlexEventBase {
|
|
1112
1111
|
readonly runId: string;
|
|
1113
1112
|
readonly messageId: string;
|
|
1114
1113
|
/** Zero-based position in the session's authoritative message sequence. */
|
|
@@ -1116,10 +1115,23 @@ export interface IFlexPartChangedEvent extends IFlexEventBase {
|
|
|
1116
1115
|
readonly partId: string;
|
|
1117
1116
|
/** Zero-based position in the message's authoritative part sequence. */
|
|
1118
1117
|
readonly partIndex: number;
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
export interface IFlexPartSnapshotEvent extends IFlexPartEventBase {
|
|
1121
|
+
readonly type: 'part.started' | 'part.updated' | 'part.completed';
|
|
1119
1122
|
readonly part: TFlexMessagePart;
|
|
1120
|
-
readonly delta?: string;
|
|
1121
1123
|
}
|
|
1122
1124
|
|
|
1125
|
+
export interface IFlexPartDeltaEvent extends IFlexPartEventBase {
|
|
1126
|
+
readonly type: 'part.delta';
|
|
1127
|
+
readonly partType: 'text' | 'reasoning';
|
|
1128
|
+
readonly delta: string;
|
|
1129
|
+
readonly baseTextUtf8Bytes: number;
|
|
1130
|
+
readonly textUtf8Bytes: number;
|
|
1131
|
+
}
|
|
1132
|
+
|
|
1133
|
+
export type TFlexPartEvent = IFlexPartSnapshotEvent | IFlexPartDeltaEvent;
|
|
1134
|
+
|
|
1123
1135
|
export interface IFlexPermissionRequestedEvent extends IFlexEventBase {
|
|
1124
1136
|
readonly type: 'permission.requested';
|
|
1125
1137
|
readonly runId: string;
|
|
@@ -1167,7 +1179,7 @@ export type TFlexHarnessEvent =
|
|
|
1167
1179
|
| IFlexSessionDeletedEvent
|
|
1168
1180
|
| IFlexRunStartedEvent
|
|
1169
1181
|
| IFlexMessageChangedEvent
|
|
1170
|
-
|
|
|
1182
|
+
| TFlexPartEvent
|
|
1171
1183
|
| IFlexPermissionRequestedEvent
|
|
1172
1184
|
| IFlexPermissionResolvedEvent
|
|
1173
1185
|
| IFlexRunFinishedEvent
|