@modelprofile.com/flexharness 10.24.0 → 11.0.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.
Files changed (135) hide show
  1. package/dist_ts/00_commitinfo_data.js +2 -2
  2. package/dist_ts/classes.codesandbox.js +1 -1
  3. package/dist_ts/classes.flexharness.admission.d.ts +17 -0
  4. package/dist_ts/classes.flexharness.admission.js +263 -0
  5. package/dist_ts/classes.flexharness.callbacks.d.ts +38 -0
  6. package/dist_ts/classes.flexharness.callbacks.js +313 -0
  7. package/dist_ts/classes.flexharness.compaction.d.ts +25 -0
  8. package/dist_ts/classes.flexharness.compaction.js +87 -0
  9. package/dist_ts/classes.flexharness.configurations.d.ts +11 -0
  10. package/dist_ts/classes.flexharness.configurations.js +137 -0
  11. package/dist_ts/classes.flexharness.core.d.ts +143 -0
  12. package/dist_ts/classes.flexharness.core.js +1538 -0
  13. package/dist_ts/classes.flexharness.d.ts +2 -437
  14. package/dist_ts/classes.flexharness.deletion.d.ts +31 -0
  15. package/dist_ts/classes.flexharness.deletion.js +396 -0
  16. package/dist_ts/classes.flexharness.imports.d.ts +24 -0
  17. package/dist_ts/classes.flexharness.imports.js +345 -0
  18. package/dist_ts/classes.flexharness.js +119 -9776
  19. package/dist_ts/classes.flexharness.lifecycle.d.ts +47 -0
  20. package/dist_ts/classes.flexharness.lifecycle.js +625 -0
  21. package/dist_ts/classes.flexharness.permissions.d.ts +19 -0
  22. package/dist_ts/classes.flexharness.permissions.js +450 -0
  23. package/dist_ts/classes.flexharness.projects.d.ts +55 -0
  24. package/dist_ts/classes.flexharness.projects.js +575 -0
  25. package/dist_ts/classes.flexharness.prompts.d.ts +44 -0
  26. package/dist_ts/classes.flexharness.prompts.js +659 -0
  27. package/dist_ts/classes.flexharness.providers.d.ts +18 -0
  28. package/dist_ts/classes.flexharness.providers.js +267 -0
  29. package/dist_ts/classes.flexharness.results.d.ts +26 -0
  30. package/dist_ts/classes.flexharness.results.js +89 -0
  31. package/dist_ts/classes.flexharness.reversions.d.ts +52 -0
  32. package/dist_ts/classes.flexharness.reversions.js +1306 -0
  33. package/dist_ts/classes.flexharness.runs.d.ts +63 -0
  34. package/dist_ts/classes.flexharness.runs.js +1058 -0
  35. package/dist_ts/classes.flexharness.sessions.d.ts +20 -0
  36. package/dist_ts/classes.flexharness.sessions.js +381 -0
  37. package/dist_ts/classes.flexharness.slashcommands.d.ts +40 -0
  38. package/dist_ts/classes.flexharness.slashcommands.js +458 -0
  39. package/dist_ts/classes.flexharness.subagents.d.ts +31 -0
  40. package/dist_ts/classes.flexharness.subagents.js +690 -0
  41. package/dist_ts/classes.flexharness.tooldispatch.d.ts +53 -0
  42. package/dist_ts/classes.flexharness.tooldispatch.js +418 -0
  43. package/dist_ts/classes.stores.js +1 -1
  44. package/dist_ts/classes.toolcatalog.js +1 -1
  45. package/dist_ts/errors.js +1 -1
  46. package/dist_ts/functions.toolpermissions.js +1 -1
  47. package/dist_ts/interfaces.d.ts +3 -3
  48. package/dist_ts/interfaces.flexharness.d.ts +455 -0
  49. package/dist_ts/interfaces.flexharness.js +2 -0
  50. package/dist_ts/utils.flexharness.d.ts +19 -0
  51. package/dist_ts/utils.flexharness.js +83 -0
  52. package/dist_ts/utils.harnessoptions.js +1 -1
  53. package/dist_ts/utils.json.js +1 -1
  54. package/dist_ts/utils.schemadeclarations.js +1 -1
  55. package/dist_ts/utils.sessionimport.js +1 -1
  56. package/dist_ts/utils.sessionmetrics.d.ts +1 -1
  57. package/dist_ts_chat/classes.chatsession.js +1 -1
  58. package/dist_ts_chat_harness/classes.transcript.js +1 -1
  59. package/dist_ts_chat_harness/functions.intents.js +1 -1
  60. package/dist_ts_chat_harness/functions.mapping.d.ts +1 -1
  61. package/dist_ts_chat_harness/functions.mapping.js +1 -1
  62. package/dist_ts_chat_harness_server/classes.chathub.d.ts +18 -7
  63. package/dist_ts_chat_harness_server/classes.chathub.js +65 -62
  64. package/dist_ts_chat_harness_server/classes.chatsubscription.d.ts +5 -3
  65. package/dist_ts_chat_harness_server/classes.chatsubscription.js +4 -4
  66. package/dist_ts_chat_harness_server/classes.scopedirectory.d.ts +17 -0
  67. package/dist_ts_chat_harness_server/classes.scopedirectory.js +49 -0
  68. package/dist_ts_chat_harness_server/classes.sessionlists.d.ts +3 -5
  69. package/dist_ts_chat_harness_server/classes.sessionlists.js +11 -12
  70. package/dist_ts_chat_harness_server/classes.turngate.d.ts +8 -2
  71. package/dist_ts_chat_harness_server/classes.turngate.js +22 -21
  72. package/dist_ts_chat_harness_server/functions.errorprojector.js +1 -1
  73. package/dist_ts_chat_harness_server/index.d.ts +3 -2
  74. package/dist_ts_chat_harness_server/index.js +3 -2
  75. package/dist_ts_chat_harness_server/interfaces.d.ts +35 -2
  76. package/dist_ts_chat_harness_server/plugins.d.ts +1 -1
  77. package/dist_ts_chat_harness_typedsocket/classes.clienttransport.d.ts +28 -3
  78. package/dist_ts_chat_harness_typedsocket/classes.clienttransport.js +71 -15
  79. package/dist_ts_chat_harness_typedsocket/classes.serverbinding.d.ts +5 -3
  80. package/dist_ts_chat_harness_typedsocket/classes.serverbinding.js +79 -16
  81. package/dist_ts_chat_harness_typedsocket/index.d.ts +2 -2
  82. package/dist_ts_chat_harness_typedsocket/index.js +1 -1
  83. package/dist_ts_chat_harness_typedsocket/interfaces.requests.d.ts +20 -11
  84. package/dist_ts_chat_web/flexchat-input.js +1 -1
  85. package/dist_ts_chat_web/flexchat-message.js +1 -1
  86. package/dist_ts_chat_web/flexchat-window.js +1 -1
  87. package/dist_ts_compaction/smartagent.compaction.js +1 -1
  88. package/dist_ts_kvm/ocr.js +1 -1
  89. package/dist_ts_ocr/classes.imageocr.js +1 -1
  90. package/dist_ts_ocr/ocr.mistral.js +1 -1
  91. package/dist_ts_stores_nosqldb/classes.nosqldbstores.js +1 -1
  92. package/dist_ts_tools/tool.browser.js +1 -1
  93. package/dist_ts_tools/tool.filesystem.js +1 -1
  94. package/dist_ts_tools/tool.shell.js +1 -1
  95. package/dist_ts_tools_node/tool.context.js +1 -1
  96. package/dist_ts_typedrequest/catalog.d.ts +2 -2
  97. package/dist_ts_typedrequest/catalog.js +1 -1
  98. package/package.json +3 -3
  99. package/ts/00_commitinfo_data.ts +1 -1
  100. package/ts/classes.flexharness.admission.ts +331 -0
  101. package/ts/classes.flexharness.callbacks.ts +352 -0
  102. package/ts/classes.flexharness.compaction.ts +167 -0
  103. package/ts/classes.flexharness.configurations.ts +167 -0
  104. package/ts/classes.flexharness.core.ts +1830 -0
  105. package/ts/classes.flexharness.deletion.ts +616 -0
  106. package/ts/classes.flexharness.imports.ts +414 -0
  107. package/ts/classes.flexharness.lifecycle.ts +786 -0
  108. package/ts/classes.flexharness.permissions.ts +535 -0
  109. package/ts/classes.flexharness.projects.ts +1006 -0
  110. package/ts/classes.flexharness.prompts.ts +857 -0
  111. package/ts/classes.flexharness.providers.ts +322 -0
  112. package/ts/classes.flexharness.results.ts +98 -0
  113. package/ts/classes.flexharness.reversions.ts +1684 -0
  114. package/ts/classes.flexharness.runs.ts +1204 -0
  115. package/ts/classes.flexharness.sessions.ts +483 -0
  116. package/ts/classes.flexharness.slashcommands.ts +705 -0
  117. package/ts/classes.flexharness.subagents.ts +860 -0
  118. package/ts/classes.flexharness.tooldispatch.ts +475 -0
  119. package/ts/classes.flexharness.ts +147 -12567
  120. package/ts/interfaces.flexharness.ts +517 -0
  121. package/ts/utils.flexharness.ts +121 -0
  122. package/ts_chat_harness_server/classes.chathub.ts +68 -61
  123. package/ts_chat_harness_server/classes.chatsubscription.ts +7 -5
  124. package/ts_chat_harness_server/classes.scopedirectory.ts +67 -0
  125. package/ts_chat_harness_server/classes.sessionlists.ts +11 -19
  126. package/ts_chat_harness_server/classes.turngate.ts +28 -21
  127. package/ts_chat_harness_server/index.ts +4 -5
  128. package/ts_chat_harness_server/interfaces.ts +35 -2
  129. package/ts_chat_harness_server/plugins.ts +0 -3
  130. package/ts_chat_harness_server/readme.md +6 -4
  131. package/ts_chat_harness_typedsocket/classes.clienttransport.ts +92 -23
  132. package/ts_chat_harness_typedsocket/classes.serverbinding.ts +88 -16
  133. package/ts_chat_harness_typedsocket/index.ts +4 -2
  134. package/ts_chat_harness_typedsocket/interfaces.requests.ts +15 -11
  135. package/ts_chat_harness_typedsocket/readme.md +7 -3
@@ -0,0 +1,167 @@
1
+ import * as plugins from './plugins.js';
2
+ import {
3
+ FlexHarnessAbortError,
4
+ FlexHarnessSlashCommandReentryError,
5
+ FlexHarnessSlashCommandUnavailableError,
6
+ } from './errors.js';
7
+ import type {
8
+ IFlexAgentContextCompactionOptions,
9
+ IFlexAgentContextInvocation,
10
+ IFlexCompactSessionOptions,
11
+ } from './interfaces.js';
12
+ import { validateCompactSessionOptions } from './utils.validation.js';
13
+ import type {
14
+ ICompactorInvocation,
15
+ IStoredSessionState,
16
+ IStorageState,
17
+ IActiveRun,
18
+ } from './interfaces.flexharness.js';
19
+ import type { FlexHarnessCore } from './classes.flexharness.core.js';
20
+
21
+ /** Compaction hooks: compactor contexts and session compaction. */
22
+ export class FlexHarnessCompaction<TScope> {
23
+ public readonly compactorInvocationContext = new plugins.AsyncLocalStorage<
24
+ ICompactorInvocation<TScope>
25
+ >();
26
+ public readonly deferredCompactorContexts = new WeakMap<
27
+ IFlexAgentContextInvocation<unknown>,
28
+ IFlexAgentContextInvocation<unknown>
29
+ >();
30
+
31
+ constructor(private readonly core: FlexHarnessCore<TScope>) {}
32
+
33
+ public async compactSession(
34
+ scopeId: string,
35
+ sessionId: string,
36
+ options: IFlexCompactSessionOptions = {},
37
+ ): Promise<void> {
38
+ const { modelHint } = validateCompactSessionOptions(options);
39
+ const { scope, state } = await this.core.resolveState(scopeId);
40
+ const stored = this.core.requireSession(state, sessionId);
41
+ this.core.assertSessionWritable(stored);
42
+ const invocationOwner = this.core.commands.slashCommandInvocationContext.getStore();
43
+ if (invocationOwner?.sessionKey === this.core.commands.slashCommandSessionKey(state.storageKey, sessionId)) {
44
+ throw this.core.trustInternalError(new FlexHarnessSlashCommandReentryError(sessionId));
45
+ }
46
+ this.core.assertStateAcceptingWork(state);
47
+ if (!this.core.agentSessionPolicy.contextCompactor) {
48
+ throw new FlexHarnessSlashCommandUnavailableError(
49
+ 'compact',
50
+ 'No context compactor is configured.',
51
+ );
52
+ }
53
+ this.core.commands.requireSessionAvailableForSlashCommand(state, stored, 'compact');
54
+ await this.core.commands.trackSlashCommandExecution(
55
+ scopeId,
56
+ state,
57
+ sessionId,
58
+ 'operation',
59
+ undefined,
60
+ async (signal) => {
61
+ await this.core.reversions.commitRevertedBranch(state, stored, scopeId, scope.scope);
62
+ await this.compactStoredSession(scopeId, scope.scope, state, stored, modelHint, signal);
63
+ },
64
+ );
65
+ }
66
+
67
+ public async compactStoredSession(
68
+ scopeId: string,
69
+ scope: TScope,
70
+ state: IStorageState,
71
+ stored: IStoredSessionState,
72
+ modelHint: string | undefined,
73
+ signal?: AbortSignal,
74
+ ): Promise<void> {
75
+ try {
76
+ await this.withCompactorContext(
77
+ this.createCompactorContext(
78
+ scopeId,
79
+ scope,
80
+ state.storageKey,
81
+ stored.session.sessionId,
82
+ modelHint,
83
+ ),
84
+ () => stored.agentSession.compact(signal === undefined ? {} : { abort: signal }),
85
+ );
86
+ } catch (error) {
87
+ throw this.core.projectOperationError(
88
+ error,
89
+ 'agentSession',
90
+ scopeId,
91
+ stored.session.sessionId,
92
+ 'compaction',
93
+ );
94
+ }
95
+ }
96
+
97
+ public abortCompactorLifecycle(stored: IStoredSessionState, reason: FlexHarnessAbortError): void {
98
+ if (!stored.compactorLifecycleController.signal.aborted) {
99
+ stored.compactorLifecycleController.abort(reason);
100
+ }
101
+ }
102
+
103
+ public createCompactorContext(
104
+ scopeId: string,
105
+ scope: TScope,
106
+ storageKey: string,
107
+ sessionId: string,
108
+ modelHint?: string,
109
+ ): ICompactorInvocation<TScope> {
110
+ return Object.freeze({
111
+ scopeId,
112
+ scope,
113
+ storageKey,
114
+ sessionId,
115
+ ...(modelHint === undefined ? {} : { modelHint }),
116
+ });
117
+ }
118
+
119
+ /**
120
+ * The model the compacted work was dispatched on: the resolved model of the run whose context
121
+ * overflowed, or the model hint a manual compaction was requested with. Retention states none.
122
+ */
123
+ public compactionModel(
124
+ state: IStorageState,
125
+ sessionId: string,
126
+ ambientContext: IFlexAgentContextInvocation<TScope>,
127
+ reason: IFlexAgentContextCompactionOptions['reason'],
128
+ modelHint: string | undefined,
129
+ ): Pick<IFlexAgentContextCompactionOptions<TScope>, 'resolvedModel' | 'modelHint'> {
130
+ if (reason === 'manual') return modelHint === undefined ? {} : { modelHint };
131
+ if (reason !== 'context-overflow' && reason !== 'context-budget') return {};
132
+ const run = state.activeRuns.get(sessionId);
133
+ if (
134
+ !run
135
+ || (ambientContext !== run.originCompactorContext && ambientContext !== run.deferredCompactorContext)
136
+ ) {
137
+ throw new Error('Context-overflow compaction is missing its exact FlexHarness run.');
138
+ }
139
+ const resolved = run.modelResolution;
140
+ if (!resolved) throw new Error('Context-overflow compaction ran before its run resolved a model.');
141
+ return {
142
+ resolvedModel: Object.freeze({ ...resolved, identity: Object.freeze({ ...resolved.identity }) }),
143
+ };
144
+ }
145
+
146
+ public withCompactorContext<TResult>(
147
+ context: IFlexAgentContextInvocation<unknown>,
148
+ operation: () => TResult,
149
+ ): TResult {
150
+ return this.compactorInvocationContext.run(
151
+ context as IFlexAgentContextInvocation<TScope>,
152
+ operation,
153
+ );
154
+ }
155
+
156
+ public createRunCompactorContext(run: IActiveRun): IFlexAgentContextInvocation<TScope> {
157
+ return run.originCompactorContext as IFlexAgentContextInvocation<TScope>;
158
+ }
159
+
160
+ public effectiveRunCompactorContext(run: IActiveRun): IFlexAgentContextInvocation<TScope> {
161
+ return (run.deferredCompactorContext ?? run.originCompactorContext) as IFlexAgentContextInvocation<TScope>;
162
+ }
163
+
164
+ public withRunCompactorContext<TResult>(run: IActiveRun, operation: () => TResult): TResult {
165
+ return this.withCompactorContext(this.effectiveRunCompactorContext(run), operation);
166
+ }
167
+ }
@@ -0,0 +1,167 @@
1
+ import { FlexHarnessAbortError, FlexHarnessValidationError } from './errors.js';
2
+ import {
3
+ normalizeAllowedTools,
4
+ normalizeSlashCommands,
5
+ normalizeSubagents,
6
+ } from './utils.harnessoptions.js';
7
+ import type {
8
+ IStoredSessionState,
9
+ IStorageState,
10
+ IResolvedSessionConfiguration,
11
+ ISessionConfigurationOwner,
12
+ } from './interfaces.flexharness.js';
13
+ import { requireSessionGeneration } from './utils.flexharness.js';
14
+ import type { FlexHarnessCore } from './classes.flexharness.core.js';
15
+
16
+ /** Session configurations from the session configuration resolver, and their owners. */
17
+ export class FlexHarnessSessionConfigurations<TScope> {
18
+ public readonly sessionConfigurations = new Map<string, ISessionConfigurationOwner<TScope>>();
19
+
20
+ constructor(private readonly core: FlexHarnessCore<TScope>) {}
21
+
22
+ public async resolveSessionConfiguration(
23
+ scopeId: string,
24
+ scope: TScope,
25
+ state: IStorageState,
26
+ stored: IStoredSessionState,
27
+ signal?: AbortSignal,
28
+ ): Promise<IResolvedSessionConfiguration<TScope>> {
29
+ const configurationRef = stored.session.configurationRef;
30
+ if (configurationRef === undefined) {
31
+ return { subagents: this.core.subagents, slashCommands: this.core.slashCommands };
32
+ }
33
+ const sessionId = stored.session.sessionId;
34
+ const generation = requireSessionGeneration(stored.session);
35
+ const key = JSON.stringify([
36
+ state.storageKey,
37
+ sessionId,
38
+ generation.sessionGenerationId,
39
+ generation.sessionGenerationSequence,
40
+ configurationRef,
41
+ ]);
42
+ let owner = this.sessionConfigurations.get(key);
43
+ if (!owner) {
44
+ const controller = new AbortController();
45
+ const parent = stored.session.parentSessionId === undefined
46
+ ? undefined
47
+ : state.sessions.get(stored.session.parentSessionId);
48
+ if (stored.session.parentSessionId !== undefined && !parent) {
49
+ throw this.core.trustInternalError(new FlexHarnessAbortError('The session parent is no longer available.'));
50
+ }
51
+ const parentGeneration = parent === undefined ? undefined : requireSessionGeneration(parent.session);
52
+ const context = Object.freeze({
53
+ scopeId,
54
+ scope,
55
+ storageKey: state.storageKey,
56
+ sessionId,
57
+ ...generation,
58
+ configurationRef,
59
+ ...(parent === undefined ? {} : {
60
+ parentSessionId: parent.session.sessionId,
61
+ parentSessionGenerationId: parentGeneration!.sessionGenerationId,
62
+ parentSessionGenerationSequence: parentGeneration!.sessionGenerationSequence,
63
+ }),
64
+ ...(stored.session.agent === undefined ? {} : { agent: stored.session.agent }),
65
+ depth: stored.session.depth ?? 0,
66
+ signal: controller.signal,
67
+ });
68
+ let rejectAbort!: (reason: unknown) => void;
69
+ const aborted = new Promise<never>((_resolve, reject) => { rejectAbort = reject; });
70
+ const onAbort = () => rejectAbort(controller.signal.reason);
71
+ controller.signal.addEventListener('abort', onAbort, { once: true });
72
+ const resolved = Promise.resolve().then(() => {
73
+ if (!this.core.sessionConfigurationResolver) {
74
+ throw new Error('A sessionConfigurationResolver is required for bound sessions.');
75
+ }
76
+ return this.core.sessionConfigurationResolver.resolveSessionConfiguration(context);
77
+ });
78
+ const completion = Promise.race([resolved, aborted]).then((configuration) => {
79
+ controller.signal.throwIfAborted();
80
+ if (
81
+ state.lifecycle !== 'active'
82
+ || state.sessions.get(sessionId) !== stored
83
+ || stored.session.configurationRef !== configurationRef
84
+ || stored.session.sessionGenerationId !== generation.sessionGenerationId
85
+ || stored.session.sessionGenerationSequence !== generation.sessionGenerationSequence
86
+ ) {
87
+ throw this.core.trustInternalError(new FlexHarnessAbortError(
88
+ 'The session configuration lost its session generation ownership.',
89
+ ));
90
+ }
91
+ if (
92
+ !configuration
93
+ || typeof configuration !== 'object'
94
+ || Array.isArray(configuration)
95
+ || ![Object.prototype, null].includes(Object.getPrototypeOf(configuration))
96
+ || Reflect.ownKeys(configuration).some((name) =>
97
+ typeof name !== 'string' || !['subagents', 'slashCommands', 'allowedTools', 'permissionPolicy'].includes(name))
98
+ ) throw new FlexHarnessValidationError('Resolved session configuration is invalid.');
99
+ if (configuration.permissionPolicy !== undefined && typeof configuration.permissionPolicy !== 'function') {
100
+ throw new FlexHarnessValidationError('Resolved session permissionPolicy must be a function.');
101
+ }
102
+ return Object.freeze({
103
+ subagents: normalizeSubagents(configuration.subagents),
104
+ slashCommands: normalizeSlashCommands(configuration.slashCommands),
105
+ allowedTools: normalizeAllowedTools(configuration.allowedTools),
106
+ permissionPolicy: configuration.permissionPolicy,
107
+ });
108
+ }).catch((error: unknown) => {
109
+ if (this.sessionConfigurations.get(key)?.completion === completion) {
110
+ this.sessionConfigurations.delete(key);
111
+ }
112
+ if (controller.signal.aborted) throw controller.signal.reason;
113
+ throw this.core.projectOperationError(
114
+ error,
115
+ 'sessionConfigurationResolver',
116
+ scopeId,
117
+ sessionId,
118
+ 'session-configuration',
119
+ );
120
+ }).finally(() => {
121
+ controller.signal.removeEventListener('abort', onAbort);
122
+ const current = this.sessionConfigurations.get(key);
123
+ if (current?.completion === completion) current.settled = true;
124
+ });
125
+ owner = { storageKey: state.storageKey, sessionId, controller, completion, settled: false, waiters: 0 };
126
+ this.sessionConfigurations.set(key, owner);
127
+ }
128
+ owner.waiters++;
129
+ let onConsumerAbort: (() => void) | undefined;
130
+ const consumerAbort = signal && new Promise<never>((_resolve, reject) => {
131
+ onConsumerAbort = () => reject(signal.reason ?? this.core.trustInternalError(
132
+ new FlexHarnessAbortError('Session configuration resolution was aborted.'),
133
+ ));
134
+ signal.addEventListener('abort', onConsumerAbort, { once: true });
135
+ if (signal.aborted) onConsumerAbort();
136
+ });
137
+ try {
138
+ return await (consumerAbort
139
+ ? Promise.race([owner.completion, consumerAbort])
140
+ : owner.completion);
141
+ } finally {
142
+ if (signal && onConsumerAbort) signal.removeEventListener('abort', onConsumerAbort);
143
+ owner.waiters--;
144
+ if (owner.waiters === 0 && !owner.settled && !owner.controller.signal.aborted) {
145
+ if (this.sessionConfigurations.get(key) === owner) this.sessionConfigurations.delete(key);
146
+ owner.controller.abort(this.core.trustInternalError(new FlexHarnessAbortError(
147
+ 'Session configuration resolution has no active callers.',
148
+ )));
149
+ }
150
+ }
151
+ }
152
+
153
+ public abortSessionConfigurations(
154
+ storageKey: string,
155
+ reason: FlexHarnessAbortError,
156
+ sessionIds?: ReadonlySet<string>,
157
+ ): Promise<void> | undefined {
158
+ const owners = [...this.sessionConfigurations.entries()].filter(([, owner]) =>
159
+ owner.storageKey === storageKey && (sessionIds === undefined || sessionIds.has(owner.sessionId)));
160
+ if (owners.length === 0) return undefined;
161
+ for (const [key, owner] of owners) {
162
+ this.sessionConfigurations.delete(key);
163
+ if (!owner.controller.signal.aborted) owner.controller.abort(reason);
164
+ }
165
+ return Promise.allSettled(owners.map(([, owner]) => owner.completion)).then(() => undefined);
166
+ }
167
+ }