@modelprofile.com/flexharness-agent 9.9.1 → 9.10.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.
@@ -96,9 +96,85 @@ export const getAgentGenerationTransactions = (events) => {
96
96
  return transactions;
97
97
  };
98
98
  export const isTransactionalGeneration = (events, generationId) => getAgentGenerationTransactions(events).has(generationId);
99
+ /** The model output that closes a tool call its stopped generation left without a result. */
100
+ export const INTERRUPTED_TOOL_CALL_RESULT = 'The tool call was interrupted before its result was recorded; its effect is unknown.';
101
+ const isModelOutputEvent = (event) => event.type === 'assistant-message'
102
+ || event.type === 'tool-call'
103
+ || event.type === 'tool-result'
104
+ || event.type === 'model-message';
105
+ /**
106
+ * Whether the events of a transactional generation are part of the model context. An accepted
107
+ * generation is, and so is the generation that is executing. A generation its owner stopped
108
+ * stays in the context once the model produced output in it: its prompt, the input it took in
109
+ * while it ran and what the model produced before the stop. One stopped before any model output
110
+ * left no trace in the conversation and is not shown, so its prompt can be sent again. Rejected
111
+ * generations, and generations interrupted by an abort, a failure or a restart, are not shown.
112
+ */
113
+ const isModelVisibleTransaction = (transaction, producedOutput) => transaction.state === 'accepted'
114
+ || transaction.state === 'execution-started'
115
+ || (transaction.state === 'interrupted'
116
+ && transaction.outcome?.stopped === true
117
+ && transaction.executionStarted !== undefined
118
+ && producedOutput.has(transaction.generationId));
119
+ /** The generations whose model produced output in `events`. */
120
+ const generationsWithModelOutput = (events) => {
121
+ const producedOutput = new Set();
122
+ for (const event of events) {
123
+ if (event.generationId && isModelOutputEvent(event))
124
+ producedOutput.add(event.generationId);
125
+ }
126
+ return producedOutput;
127
+ };
128
+ /**
129
+ * Whether the transactional generation `generationId` is part of the model context of later
130
+ * generations, by the rule `filterModelVisibleAgentEvents` applies: it was accepted, is
131
+ * executing, or was stopped by its owner after its model produced output. False for a
132
+ * generation `events` holds no transaction of.
133
+ */
134
+ export const isGenerationInModelContext = (events, generationId) => {
135
+ const transaction = getAgentGenerationTransactions(events).get(generationId);
136
+ return transaction !== undefined
137
+ && isModelVisibleTransaction(transaction, generationsWithModelOutput(events));
138
+ };
139
+ const interruptedToolResult = (toolCallId, toolName, source) => ({
140
+ id: `${source.id}:interrupted:${toolCallId}`,
141
+ timestamp: source.timestamp,
142
+ type: 'tool-result',
143
+ toolCallId,
144
+ toolName,
145
+ error: INTERRUPTED_TOOL_CALL_RESULT,
146
+ modelOutput: { type: 'error-text', value: INTERRUPTED_TOOL_CALL_RESULT },
147
+ generationId: source.generationId,
148
+ inferenceId: source.inferenceId,
149
+ causationId: source.causationId,
150
+ parentIds: [source.id],
151
+ });
99
152
  export const filterModelVisibleAgentEvents = (events) => {
100
153
  const transactions = getAgentGenerationTransactions(events);
154
+ const producedOutput = generationsWithModelOutput(events);
155
+ const resultedToolCalls = new Set();
156
+ for (const event of events) {
157
+ if (!event.generationId)
158
+ continue;
159
+ if (event.type === 'tool-result')
160
+ resultedToolCalls.add(`${event.generationId}\0${event.toolCallId}`);
161
+ if (event.type === 'assistant-message' && Array.isArray(event.content)) {
162
+ for (const part of event.content) {
163
+ if (part.type === 'tool-result') {
164
+ resultedToolCalls.add(`${event.generationId}\0${part.toolCallId}`);
165
+ }
166
+ }
167
+ }
168
+ }
101
169
  const visibleEvents = [];
170
+ /** Closes each tool call a stopped generation left open, right after the call. */
171
+ const closeOpenToolCall = (toolCallId, toolName, source) => {
172
+ const key = `${source.generationId}\0${toolCallId}`;
173
+ if (resultedToolCalls.has(key))
174
+ return;
175
+ resultedToolCalls.add(key);
176
+ visibleEvents.push(interruptedToolResult(toolCallId, toolName, source));
177
+ };
102
178
  for (const event of events) {
103
179
  if (isControlEvent(event))
104
180
  continue;
@@ -111,10 +187,21 @@ export const filterModelVisibleAgentEvents = (events) => {
111
187
  continue;
112
188
  }
113
189
  const transaction = transactions.get(event.generationId);
114
- if (!transaction
115
- || transaction.state === 'accepted'
116
- || transaction.state === 'execution-started')
117
- visibleEvents.push(event);
190
+ if (transaction && !isModelVisibleTransaction(transaction, producedOutput))
191
+ continue;
192
+ visibleEvents.push(event);
193
+ if (transaction?.state !== 'interrupted')
194
+ continue;
195
+ if (event.type === 'tool-call' && event.providerExecuted !== true) {
196
+ closeOpenToolCall(event.toolCallId, event.toolName, event);
197
+ }
198
+ else if (event.type === 'assistant-message' && Array.isArray(event.content)) {
199
+ for (const part of event.content) {
200
+ if (part.type === 'tool-call' && part.providerExecuted !== true) {
201
+ closeOpenToolCall(part.toolCallId, part.toolName, event);
202
+ }
203
+ }
204
+ }
118
205
  }
119
206
  return visibleEvents;
120
207
  };
@@ -138,4 +225,4 @@ export const getUncertainToolExecutionIntents = (events, generationId) => {
138
225
  }
139
226
  return [...uncertain.values()];
140
227
  };
141
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhZ2VudC50cmFuc2FjdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19hZ2VudC9zbWFydGFnZW50LnRyYW5zYWN0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUEyQkEsTUFBTSxjQUFjLEdBQUcsQ0FBQyxLQUFrQixFQUErQixFQUFFLENBQ3pFLEtBQUssQ0FBQyxJQUFJLEtBQUssa0JBQWtCO09BQzlCLEtBQUssQ0FBQyxJQUFJLEtBQUssOEJBQThCO09BQzdDLEtBQUssQ0FBQyxJQUFJLEtBQUssZ0NBQWdDO09BQy9DLEtBQUssQ0FBQyxJQUFJLEtBQUssb0JBQW9CO09BQ25DLEtBQUssQ0FBQyxJQUFJLEtBQUssdUJBQXVCO09BQ3RDLEtBQUssQ0FBQyxJQUFJLEtBQUssK0JBQStCLENBQUM7QUFFcEQsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsQ0FDNUMsTUFBOEIsRUFDWSxFQUFFO0lBZTVDLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFtQyxDQUFDO0lBQy9ELE1BQU0sUUFBUSxHQUFHLENBQUMsWUFBb0IsRUFBMkIsRUFBRTtRQUNqRSxJQUFJLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLEtBQUssR0FBRztnQkFDTixVQUFVLEVBQUUsQ0FBQztnQkFDYixVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUNkLFlBQVksRUFBRSxDQUFDO2dCQUNmLFlBQVksRUFBRSxDQUFDLENBQUM7Z0JBQ2hCLGNBQWMsRUFBRSxDQUFDO2dCQUNqQixjQUFjLEVBQUUsQ0FBQyxDQUFDO2dCQUNsQixZQUFZLEVBQUUsQ0FBQztnQkFDZixZQUFZLEVBQUUsQ0FBQyxDQUFDO2FBQ2pCLENBQUM7WUFDRixXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsT0FB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
228
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRhZ2VudC50cmFuc2FjdGlvbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19hZ2VudC9zbWFydGFnZW50LnRyYW5zYWN0aW9ucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUE0QkEsTUFBTSxjQUFjLEdBQUcsQ0FBQyxLQUFrQixFQUErQixFQUFFLENBQ3pFLEtBQUssQ0FBQyxJQUFJLEtBQUssa0JBQWtCO09BQzlCLEtBQUssQ0FBQyxJQUFJLEtBQUssOEJBQThCO09BQzdDLEtBQUssQ0FBQyxJQUFJLEtBQUssZ0NBQWdDO09BQy9DLEtBQUssQ0FBQyxJQUFJLEtBQUssb0JBQW9CO09BQ25DLEtBQUssQ0FBQyxJQUFJLEtBQUssdUJBQXVCO09BQ3RDLEtBQUssQ0FBQyxJQUFJLEtBQUssK0JBQStCLENBQUM7QUFFcEQsTUFBTSxDQUFDLE1BQU0sOEJBQThCLEdBQUcsQ0FDNUMsTUFBOEIsRUFDWSxFQUFFO0lBZTVDLE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFtQyxDQUFDO0lBQy9ELE1BQU0sUUFBUSxHQUFHLENBQUMsWUFBb0IsRUFBMkIsRUFBRTtRQUNqRSxJQUFJLEtBQUssR0FBRyxXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzFDLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLEtBQUssR0FBRztnQkFDTixVQUFVLEVBQUUsQ0FBQztnQkFDYixVQUFVLEVBQUUsQ0FBQyxDQUFDO2dCQUNkLFlBQVksRUFBRSxDQUFDO2dCQUNmLFlBQVksRUFBRSxDQUFDLENBQUM7Z0JBQ2hCLGNBQWMsRUFBRSxDQUFDO2dCQUNqQixjQUFjLEVBQUUsQ0FBQyxDQUFDO2dCQUNsQixZQUFZLEVBQUUsQ0FBQztnQkFDZixZQUFZLEVBQUUsQ0FBQyxDQUFDO2FBQ2pCLENBQUM7WUFDRixXQUFXLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxLQUFLLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsT0FB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
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "author": "Task Venture Capital GmbH",
3
3
  "license": "MIT",
4
4
  "name": "@modelprofile.com/flexharness-agent",
5
- "version": "9.9.1",
5
+ "version": "9.10.0",
6
6
  "type": "module",
7
7
  "description": "Standalone event-driven agent runtime with generation transactions, context and tool execution contracts.",
8
8
  "main": "./dist_ts_agent/index.js",
@@ -18,7 +18,7 @@
18
18
  }
19
19
  },
20
20
  "dependencies": {
21
- "@modelprofile.com/flexharness-models": "9.9.1",
21
+ "@modelprofile.com/flexharness-models": "9.10.0",
22
22
  "ai": "^7.0.107",
23
23
  "zod": "^4.4.1",
24
24
  "@noble/hashes": "^2.4.0",
package/readme.md CHANGED
@@ -274,10 +274,34 @@ export async function createReviewedDraft(
274
274
 
275
275
  The `review` callback belongs to your application. While awaiting acceptance, `candidate.messages` includes the candidate, but `getModelMessages()` excludes it from ordinary future context. Acceptance includes the generation; rejection keeps it in the canonical event history while excluding it from future context. Generation IDs identify transactions within a session; use a distinct ID for each new transaction.
276
276
 
277
+ `generate({ transaction, stop })` takes a second signal for the owner's stop, the way a user stops a turn. It ends the generation like `abort`, but the interrupted outcome records the stop (`stopped: true`, also accepted by `finalizeGeneration(transaction, 'interrupted', { stopped: true })` for a generation stopped after its execution completed). A stopped generation stays in future context once its model produced output: its prompt, the input it took in, the text its running model step streamed and the tool calls it issued. Each tool call without a recorded result is closed with an error result saying its effect is unknown, so the next request is well-formed for every provider. A generation stopped before any model output leaves no trace, so its prompt can be sent again without appearing twice. `isGenerationInModelContext(events, generationId)` applies the same rule to a list of events, for a caller that needs to know whether a finished generation stayed in context. Aborted and failed generations, and generations a restart interrupted, stay out of future context as before. `stop` requires a transactional generation.
278
+
277
279
  Closing a session or restoring a stored session interrupts unfinished transactions. Restoration does not automatically rerun them. Persisted transactions require an `IAgentEventStoreV2` store with `eventSchemaVersion: 2`; without a store, transactions are process-local.
278
280
 
279
281
  A rejected generation does not roll back external tool effects. The runtime records transactional tool-execution intents and results. If a crash leaves an intent without a known result, inspect `listUncertainToolExecutions()` and reconcile the external operation through `reconcileToolExecution()` before treating its outcome as known. This is not a general exactly-once guarantee for external services.
280
282
 
283
+ ## Take input while a generation runs
284
+
285
+ Pass an `AgentPendingInputQueue` to `generate({ pendingInput })` to let the user steer a running generation. The generation takes waiting input in at every step boundary, after the tool results of the previous model step are recorded and before the next model call, and records each input as a user message of the generation (`inputId` set). A running tool call is never interrupted. `onInputApplied` is called for each input once it is durable, before the next model call; every durable input is reported, also when reporting an earlier one throws, and the generation then fails with that error. Input the generation could not record durably counts as never taken in: the generation gives it back to the queue with `restore()`.
286
+
287
+ ```typescript
288
+ import { AgentPendingInputQueue } from '@modelprofile.com/flexharness-agent';
289
+
290
+ const pendingInput = new AgentPendingInputQueue();
291
+ const transaction = await session.beginGeneration('Plan the release.');
292
+ const generation = session.generate({
293
+ transaction,
294
+ pendingInput,
295
+ onInputApplied: ({ inputId, eventId }) => markApplied(inputId, eventId),
296
+ });
297
+ // While the generation runs:
298
+ pendingInput.add({ inputId: 'steer-1', content: 'Keep the migration out of it.' });
299
+ await generation;
300
+ const unapplied = pendingInput.close(); // input the generation never took in
301
+ ```
302
+
303
+ The generation closes the queue when it ends, whether it completed, failed or was aborted. `close()` returns the inputs it never took in, the same list on every call once the generation has ended; input that arrives during the last model step is among them, and so is input the generation drained but could not record durably. After closing, `add()` throws `AgentPendingInputRejectedError` with reason `closed`, and a reused `inputId` is refused with reason `duplicate`. The caller decides what becomes of unapplied input, for example sending it as the next turn.
304
+
281
305
  ## Events, storage and context
282
306
 
283
307
  Canonical events retain user and assistant messages, tool calls and results, runtime events, compaction records and transaction outcomes. `getEvents()` returns this history; `getModelMessages()` projects the model-visible conversation through the configured `contextBuilder`, which defaults to `buildModelMessages`.
@@ -20,8 +20,13 @@ import {
20
20
  type IUserMessageEvent,
21
21
  type TAgentEvent,
22
22
  type TAgentGenerationOutcome,
23
+ type TAgentToolCallPart,
23
24
  type TAgentToolResultOutput,
24
25
  } from './smartagent.events.js';
26
+ import type {
27
+ AgentPendingInputQueue,
28
+ IAgentAppliedInput,
29
+ } from './smartagent.pendinginput.js';
25
30
  import {
26
31
  AgentGenerationLeaseCleanupError,
27
32
  ContextOverflowError,
@@ -31,6 +36,7 @@ import {
31
36
  type IAgentGenerationLease,
32
37
  type IAgentCompactOptions,
33
38
  type IAgentBeginGenerationOptions,
39
+ type IAgentFinalizeGenerationOptions,
34
40
  type IAgentSession,
35
41
  type IAgentSessionAbortOptions,
36
42
  type IAgentSessionChange,
@@ -101,8 +107,11 @@ interface IScheduledGeneration {
101
107
  cache?: TAgentCacheSetting;
102
108
  maxSteps?: number;
103
109
  abort?: AbortSignal;
110
+ stop?: AbortSignal;
104
111
  transaction?: IAgentGenerationHandle;
105
112
  prepare?: TAgentGenerationPrepare;
113
+ pendingInput?: AgentPendingInputQueue;
114
+ onInputApplied?: (input: IAgentAppliedInput) => void | Promise<void>;
106
115
  timer: NodeJS.Timeout;
107
116
  controller: AbortController;
108
117
  removeAbortListener: () => void;
@@ -821,6 +830,7 @@ export class AgentSessionEngine implements IAgentSession {
821
830
  generationId: string,
822
831
  outcome: TAgentGenerationOutcome,
823
832
  reason?: string,
833
+ stopped = false,
824
834
  ): Promise<void> {
825
835
  const transaction = this.transaction(generationId);
826
836
  if (
@@ -853,6 +863,7 @@ export class AgentSessionEngine implements IAgentSession {
853
863
  generationId,
854
864
  outcome,
855
865
  reason,
866
+ ...(stopped ? { stopped: true } : {}),
856
867
  parentIds: [parent.id],
857
868
  }));
858
869
  await this.flushPersistence();
@@ -874,6 +885,7 @@ export class AgentSessionEngine implements IAgentSession {
874
885
  public finalizeGeneration(
875
886
  transaction: IAgentGenerationHandle,
876
887
  outcome: TAgentGenerationOutcome,
888
+ options: IAgentFinalizeGenerationOptions = {},
877
889
  ): Promise<void> {
878
890
  const capabilityError = this.transactionalStoreCapabilityError();
879
891
  if (capabilityError) return Promise.reject(capabilityError);
@@ -881,6 +893,9 @@ export class AgentSessionEngine implements IAgentSession {
881
893
  if (!['accepted', 'rejected', 'interrupted'].includes(outcome)) {
882
894
  throw new Error(`Invalid transactional generation outcome "${String(outcome)}".`);
883
895
  }
896
+ if (options.stopped === true && outcome !== 'interrupted') {
897
+ throw new Error('Only an interrupted transactional generation can be stopped.');
898
+ }
884
899
  const state = this.verifyGenerationClaim(transaction);
885
900
  if (!('begun' in state)) {
886
901
  if (state.outcome === outcome) return;
@@ -888,7 +903,12 @@ export class AgentSessionEngine implements IAgentSession {
888
903
  `Transactional generation "${transaction.generationId}" already has outcome "${state.outcome}".`,
889
904
  );
890
905
  }
891
- await this.appendGenerationOutcome(transaction.generationId, outcome);
906
+ await this.appendGenerationOutcome(
907
+ transaction.generationId,
908
+ outcome,
909
+ undefined,
910
+ options.stopped === true,
911
+ );
892
912
  });
893
913
  }
894
914
 
@@ -1024,6 +1044,9 @@ export class AgentSessionEngine implements IAgentSession {
1024
1044
  ? this.transactionalStoreCapabilityError()
1025
1045
  : undefined;
1026
1046
  if (capabilityError) return Promise.reject(capabilityError);
1047
+ if (options.stop && !options.transaction) {
1048
+ return Promise.reject(new Error('A stop signal requires a transactional generation.'));
1049
+ }
1027
1050
  if (!options.key.trim()) return Promise.reject(new Error('Scheduled generation key must not be empty.'));
1028
1051
  const debounceMs = options.debounceMs ?? 50;
1029
1052
  if (!Number.isSafeInteger(debounceMs) || debounceMs < 0) {
@@ -1039,7 +1062,10 @@ export class AgentSessionEngine implements IAgentSession {
1039
1062
  || existing.cache !== options.cache
1040
1063
  || existing.maxSteps !== options.maxSteps
1041
1064
  || existing.abort !== options.abort
1065
+ || existing.stop !== options.stop
1042
1066
  || existing.prepare !== options.prepare
1067
+ || existing.pendingInput !== options.pendingInput
1068
+ || existing.onInputApplied !== options.onInputApplied
1043
1069
  || existing.transaction?.generationId !== options.transaction?.generationId
1044
1070
  || existing.transaction?.claimToken !== options.transaction?.claimToken
1045
1071
  ) {
@@ -1053,8 +1079,9 @@ export class AgentSessionEngine implements IAgentSession {
1053
1079
  return existing.promise;
1054
1080
  }
1055
1081
 
1056
- if (options.abort?.aborted) {
1057
- const abortReason = options.abort.reason ?? new DOMException('Aborted', 'AbortError');
1082
+ const endedBy = options.abort?.aborted ? options.abort : options.stop?.aborted ? options.stop : undefined;
1083
+ if (endedBy) {
1084
+ const abortReason = endedBy.reason ?? new DOMException('Aborted', 'AbortError');
1058
1085
  if (!options.transaction) return Promise.reject(abortReason);
1059
1086
  return this.queueExclusive(async () => {
1060
1087
  const transaction = this.verifyGenerationClaim(options.transaction!);
@@ -1082,9 +1109,11 @@ export class AgentSessionEngine implements IAgentSession {
1082
1109
  const controller = new AbortController();
1083
1110
  const onAbort = () => this.cancelScheduledGeneration(
1084
1111
  options.key,
1085
- options.abort?.reason ?? new DOMException('Aborted', 'AbortError'),
1112
+ (options.abort?.aborted ? options.abort.reason : options.stop?.reason)
1113
+ ?? new DOMException('Aborted', 'AbortError'),
1086
1114
  );
1087
1115
  options.abort?.addEventListener('abort', onAbort, { once: true });
1116
+ options.stop?.addEventListener('abort', onAbort, { once: true });
1088
1117
  const scheduled: IScheduledGeneration = {
1089
1118
  state: 'debouncing',
1090
1119
  debounceMs,
@@ -1095,11 +1124,17 @@ export class AgentSessionEngine implements IAgentSession {
1095
1124
  cache: options.cache,
1096
1125
  maxSteps: options.maxSteps,
1097
1126
  abort: options.abort,
1127
+ stop: options.stop,
1098
1128
  transaction: options.transaction,
1099
1129
  prepare: options.prepare,
1130
+ pendingInput: options.pendingInput,
1131
+ onInputApplied: options.onInputApplied,
1100
1132
  timer: setTimeout(() => this.startScheduledGeneration(options.key), debounceMs),
1101
1133
  controller,
1102
- removeAbortListener: () => options.abort?.removeEventListener('abort', onAbort),
1134
+ removeAbortListener: () => {
1135
+ options.abort?.removeEventListener('abort', onAbort);
1136
+ options.stop?.removeEventListener('abort', onAbort);
1137
+ },
1103
1138
  promise,
1104
1139
  resolve,
1105
1140
  reject,
@@ -1120,8 +1155,11 @@ export class AgentSessionEngine implements IAgentSession {
1120
1155
  cache: scheduled.cache,
1121
1156
  maxSteps: scheduled.maxSteps,
1122
1157
  abort: scheduled.controller.signal,
1158
+ stop: scheduled.stop,
1123
1159
  transaction: scheduled.transaction,
1124
1160
  prepare: scheduled.prepare,
1161
+ pendingInput: scheduled.pendingInput,
1162
+ onInputApplied: scheduled.onInputApplied,
1125
1163
  }).then(
1126
1164
  (result) => this.settleScheduledGeneration(key, scheduled, () => scheduled.resolve(result)),
1127
1165
  (error) => this.settleScheduledGeneration(key, scheduled, () => scheduled.reject(error)),
@@ -1149,6 +1187,7 @@ export class AgentSessionEngine implements IAgentSession {
1149
1187
  const cancellationReason = reason
1150
1188
  ?? new DOMException('Scheduled generation cancelled', 'AbortError');
1151
1189
  if (!scheduled.controller.signal.aborted) scheduled.controller.abort(cancellationReason);
1190
+ scheduled.pendingInput?.close();
1152
1191
  if (!scheduled.transaction) {
1153
1192
  scheduled.reject(cancellationReason);
1154
1193
  return true;
@@ -1720,6 +1759,9 @@ export class AgentSessionEngine implements IAgentSession {
1720
1759
  ? this.transactionalStoreCapabilityError()
1721
1760
  : undefined;
1722
1761
  if (capabilityError) return Promise.reject(capabilityError);
1762
+ if (options.stop && !options.transaction) {
1763
+ return Promise.reject(new Error('A stop signal requires a transactional generation.'));
1764
+ }
1723
1765
  const run = this.generationQueue.then(async () => {
1724
1766
  if (!options.transaction) options.abort?.throwIfAborted();
1725
1767
  if (!options.transaction && this.sessionAbortController.signal.aborted) {
@@ -1730,6 +1772,9 @@ export class AgentSessionEngine implements IAgentSession {
1730
1772
  if (this.maintenanceError !== undefined) throw this.maintenanceError;
1731
1773
  await this.runEventRetentionLocked();
1732
1774
  return this.generateLocked(options);
1775
+ }).finally(() => {
1776
+ // The generation takes no further input; what it never took in stays with the queue.
1777
+ options.pendingInput?.close();
1733
1778
  });
1734
1779
  this.generationQueue = run.then(() => undefined, () => undefined);
1735
1780
  // A transactional generation is not raced against its abort signal: it settles when its
@@ -1801,6 +1846,7 @@ export class AgentSessionEngine implements IAgentSession {
1801
1846
  this.sessionAbortController.signal,
1802
1847
  generationAbortController.signal,
1803
1848
  options.abort,
1849
+ options.stop,
1804
1850
  ]);
1805
1851
 
1806
1852
  let lease: IAgentGenerationLease | undefined;
@@ -1862,6 +1908,8 @@ export class AgentSessionEngine implements IAgentSession {
1862
1908
  const reportCompactionUsage: TAgentModelCallUsageReporter = (call) =>
1863
1909
  recordModelCallUsage({ ...call, source: 'compaction', generationId });
1864
1910
  let currentInferenceId: string | undefined;
1911
+ /** Text the current inference streamed so far, kept if the inference is interrupted. */
1912
+ let inferenceText = '';
1865
1913
  let latestInferenceVisibleIds = new Set(this.events.map((event) => event.id));
1866
1914
  const completedInferenceIds = new Set<string>();
1867
1915
  const reasoningTextById = new Map<string, string>();
@@ -1889,10 +1937,90 @@ export class AgentSessionEngine implements IAgentSession {
1889
1937
  : undefined,
1890
1938
  }));
1891
1939
  currentInferenceId = marker.id;
1940
+ inferenceText = '';
1892
1941
  latestInferenceVisibleIds = new Set(this.events.map((event) => event.id));
1893
1942
  await this.flushPersistence();
1894
1943
  return marker.id;
1895
1944
  };
1945
+ const applyPendingInput = async (): Promise<void> => {
1946
+ const inputs = options.pendingInput?.drain() ?? [];
1947
+ if (inputs.length === 0) return;
1948
+ const applied: IAgentAppliedInput[] = [];
1949
+ try {
1950
+ for (const input of inputs) {
1951
+ const event = this.commitEvent(createAgentEvent<IUserMessageEvent>({
1952
+ type: 'user-message',
1953
+ content: input.content,
1954
+ inputId: input.inputId,
1955
+ generationId,
1956
+ parentIds: this.events.length > 0
1957
+ ? [this.events[this.events.length - 1].id]
1958
+ : undefined,
1959
+ }));
1960
+ applied.push({
1961
+ inputId: input.inputId,
1962
+ eventId: event.id,
1963
+ generationId,
1964
+ completedSteps: stepCount,
1965
+ });
1966
+ }
1967
+ await this.flushPersistence();
1968
+ } catch (error) {
1969
+ // Input that is not durable was not taken in: the queue returns it from close().
1970
+ options.pendingInput!.restore(inputs);
1971
+ throw error;
1972
+ }
1973
+ // Every durable input is reported, also when reporting an earlier one failed.
1974
+ const callbackErrors: unknown[] = [];
1975
+ for (const input of applied) {
1976
+ try {
1977
+ await this.invokeGenerationCallback(() => options.onInputApplied?.(input));
1978
+ } catch (error) {
1979
+ callbackErrors.push(error);
1980
+ }
1981
+ }
1982
+ if (callbackErrors.length === 1) throw callbackErrors[0];
1983
+ if (callbackErrors.length > 1) {
1984
+ throw new AggregateError(callbackErrors, 'Reporting applied pending input failed.');
1985
+ }
1986
+ };
1987
+ /**
1988
+ * Keeps what a stopped inference produced: the text it streamed and the tool calls it
1989
+ * issued, as one assistant message of the generation. Tool calls without a result are
1990
+ * closed when the stopped generation is rendered for the model.
1991
+ */
1992
+ const commitInterruptedInference = async (): Promise<void> => {
1993
+ const inferenceId = currentInferenceId;
1994
+ if (!options.stop?.aborted || !inferenceId || completedInferenceIds.has(inferenceId)) return;
1995
+ completedInferenceIds.add(inferenceId);
1996
+ if (this.events.some((event) =>
1997
+ event.type === 'assistant-message' && event.inferenceId === inferenceId)) return;
1998
+ const toolCallParts: TAgentToolCallPart[] = this.events
1999
+ .filter((event): event is IToolCallEvent =>
2000
+ event.type === 'tool-call'
2001
+ && event.generationId === generationId
2002
+ && event.inferenceId === inferenceId)
2003
+ .map((event) => ({
2004
+ type: 'tool-call',
2005
+ toolCallId: event.toolCallId,
2006
+ toolName: event.toolName,
2007
+ input: event.input,
2008
+ ...(event.providerExecuted === undefined ? {} : { providerExecuted: event.providerExecuted }),
2009
+ ...(event.providerOptions === undefined ? {} : { providerOptions: event.providerOptions }),
2010
+ }));
2011
+ if (!inferenceText && toolCallParts.length === 0) return;
2012
+ this.commitEvent(createAgentEvent<IAssistantMessageEvent>({
2013
+ type: 'assistant-message',
2014
+ content: [
2015
+ ...(inferenceText ? [{ type: 'text' as const, text: inferenceText }] : []),
2016
+ ...toolCallParts,
2017
+ ],
2018
+ generationId,
2019
+ inferenceId,
2020
+ causationId: inferenceId,
2021
+ }));
2022
+ await this.flushPersistence();
2023
+ };
1896
2024
  const allTools = this.wrapToolsForGeneration(
1897
2025
  generationId,
1898
2026
  runtime.tools,
@@ -1918,6 +2046,7 @@ export class AgentSessionEngine implements IAgentSession {
1918
2046
  let streamError: unknown;
1919
2047
  try {
1920
2048
  currentInferenceId = undefined;
2049
+ inferenceText = '';
1921
2050
  const result = plugins.streamText({
1922
2051
  model: runtime.model,
1923
2052
  instructions: runtime.system,
@@ -1929,6 +2058,7 @@ export class AgentSessionEngine implements IAgentSession {
1929
2058
  maxRetries: 0,
1930
2059
  abortSignal: combinedAbort.signal,
1931
2060
  prepareStep: async () => {
2061
+ await applyPendingInput();
1932
2062
  await beginInference();
1933
2063
  return { messages: this.buildContext(this.eventsByIds(latestInferenceVisibleIds)) };
1934
2064
  },
@@ -1959,7 +2089,9 @@ export class AgentSessionEngine implements IAgentSession {
1959
2089
  const chunkType = String((chunk as { type?: unknown }).type ?? '');
1960
2090
  if (chunkType === 'text-delta') {
1961
2091
  const textChunk = chunk as { delta?: string; textDelta?: string; text?: string };
1962
- this.options.onToken?.(textChunk.delta ?? textChunk.textDelta ?? textChunk.text ?? '');
2092
+ const delta = textChunk.delta ?? textChunk.textDelta ?? textChunk.text ?? '';
2093
+ inferenceText += delta;
2094
+ this.options.onToken?.(delta);
1963
2095
  return;
1964
2096
  }
1965
2097
  if (chunkType === 'tool-result') {
@@ -2245,8 +2377,11 @@ export class AgentSessionEngine implements IAgentSession {
2245
2377
  flushReasoning();
2246
2378
  const effectiveError = streamError ?? error;
2247
2379
  if (combinedAbort.signal.aborted) {
2380
+ await commitInterruptedInference();
2248
2381
  throw combinedAbort.signal.reason ?? new DOMException('Aborted', 'AbortError');
2249
2382
  }
2383
+ // A failed attempt is retried or fails the generation; its partial text is not kept.
2384
+ inferenceText = '';
2250
2385
  if (effectiveError instanceof DOMException && effectiveError.name === 'AbortError') {
2251
2386
  throw effectiveError;
2252
2387
  }
@@ -2344,6 +2479,7 @@ export class AgentSessionEngine implements IAgentSession {
2344
2479
  generationId,
2345
2480
  'interrupted',
2346
2481
  this.transactionOutcomeErrorReason(effectiveError),
2482
+ options.stop?.aborted === true,
2347
2483
  );
2348
2484
  } else {
2349
2485
  const transaction = this.transaction(generationId);
@@ -2366,6 +2502,7 @@ export class AgentSessionEngine implements IAgentSession {
2366
2502
  generationId,
2367
2503
  'interrupted',
2368
2504
  this.transactionOutcomeErrorReason(abortError),
2505
+ options.stop?.aborted === true,
2369
2506
  );
2370
2507
  throw abortError;
2371
2508
  }
package/ts_agent/index.ts CHANGED
@@ -6,6 +6,7 @@ export {
6
6
  getAgentGenerationTransactions,
7
7
  getOpenAgentGenerationTransactions,
8
8
  getUncertainToolExecutionIntents,
9
+ isGenerationInModelContext,
9
10
  isTransactionalGeneration,
10
11
  } from './smartagent.transactions.js';
11
12
  export {
@@ -13,6 +14,15 @@ export {
13
14
  createAgentEventId,
14
15
  modelMessagesToAgentEvents,
15
16
  } from './smartagent.events.js';
17
+ export {
18
+ AgentPendingInputQueue,
19
+ AgentPendingInputRejectedError,
20
+ } from './smartagent.pendinginput.js';
21
+ export type {
22
+ IAgentAppliedInput,
23
+ IAgentPendingInput,
24
+ TAgentPendingInputRejection,
25
+ } from './smartagent.pendinginput.js';
16
26
  export { ToolRegistry } from './smartagent.classes.toolregistry.js';
17
27
  export { AgentModelCallUsageRecorder } from './smartagent.usage.js';
18
28
  export type { IAgentModelCallUsageRecorderModel } from './smartagent.usage.js';
@@ -35,6 +45,7 @@ export type {
35
45
  IAgentCompactOptions,
36
46
  IAgentEventRetentionOptions,
37
47
  IAgentBeginGenerationOptions,
48
+ IAgentFinalizeGenerationOptions,
38
49
  IAgentGenerateOptions,
39
50
  IAgentGenerateResult,
40
51
  IAgentGenerationHandle,
@@ -274,10 +274,34 @@ export async function createReviewedDraft(
274
274
 
275
275
  The `review` callback belongs to your application. While awaiting acceptance, `candidate.messages` includes the candidate, but `getModelMessages()` excludes it from ordinary future context. Acceptance includes the generation; rejection keeps it in the canonical event history while excluding it from future context. Generation IDs identify transactions within a session; use a distinct ID for each new transaction.
276
276
 
277
+ `generate({ transaction, stop })` takes a second signal for the owner's stop, the way a user stops a turn. It ends the generation like `abort`, but the interrupted outcome records the stop (`stopped: true`, also accepted by `finalizeGeneration(transaction, 'interrupted', { stopped: true })` for a generation stopped after its execution completed). A stopped generation stays in future context once its model produced output: its prompt, the input it took in, the text its running model step streamed and the tool calls it issued. Each tool call without a recorded result is closed with an error result saying its effect is unknown, so the next request is well-formed for every provider. A generation stopped before any model output leaves no trace, so its prompt can be sent again without appearing twice. `isGenerationInModelContext(events, generationId)` applies the same rule to a list of events, for a caller that needs to know whether a finished generation stayed in context. Aborted and failed generations, and generations a restart interrupted, stay out of future context as before. `stop` requires a transactional generation.
278
+
277
279
  Closing a session or restoring a stored session interrupts unfinished transactions. Restoration does not automatically rerun them. Persisted transactions require an `IAgentEventStoreV2` store with `eventSchemaVersion: 2`; without a store, transactions are process-local.
278
280
 
279
281
  A rejected generation does not roll back external tool effects. The runtime records transactional tool-execution intents and results. If a crash leaves an intent without a known result, inspect `listUncertainToolExecutions()` and reconcile the external operation through `reconcileToolExecution()` before treating its outcome as known. This is not a general exactly-once guarantee for external services.
280
282
 
283
+ ## Take input while a generation runs
284
+
285
+ Pass an `AgentPendingInputQueue` to `generate({ pendingInput })` to let the user steer a running generation. The generation takes waiting input in at every step boundary, after the tool results of the previous model step are recorded and before the next model call, and records each input as a user message of the generation (`inputId` set). A running tool call is never interrupted. `onInputApplied` is called for each input once it is durable, before the next model call; every durable input is reported, also when reporting an earlier one throws, and the generation then fails with that error. Input the generation could not record durably counts as never taken in: the generation gives it back to the queue with `restore()`.
286
+
287
+ ```typescript
288
+ import { AgentPendingInputQueue } from '@modelprofile.com/flexharness-agent';
289
+
290
+ const pendingInput = new AgentPendingInputQueue();
291
+ const transaction = await session.beginGeneration('Plan the release.');
292
+ const generation = session.generate({
293
+ transaction,
294
+ pendingInput,
295
+ onInputApplied: ({ inputId, eventId }) => markApplied(inputId, eventId),
296
+ });
297
+ // While the generation runs:
298
+ pendingInput.add({ inputId: 'steer-1', content: 'Keep the migration out of it.' });
299
+ await generation;
300
+ const unapplied = pendingInput.close(); // input the generation never took in
301
+ ```
302
+
303
+ The generation closes the queue when it ends, whether it completed, failed or was aborted. `close()` returns the inputs it never took in, the same list on every call once the generation has ended; input that arrives during the last model step is among them, and so is input the generation drained but could not record durably. After closing, `add()` throws `AgentPendingInputRejectedError` with reason `closed`, and a reused `inputId` is refused with reason `duplicate`. The caller decides what becomes of unapplied input, for example sending it as the next turn.
304
+
281
305
  ## Events, storage and context
282
306
 
283
307
  Canonical events retain user and assistant messages, tool calls and results, runtime events, compaction records and transaction outcomes. `getEvents()` returns this history; `getModelMessages()` projects the model-visible conversation through the configured `contextBuilder`, which defaults to `buildModelMessages`.
@@ -35,6 +35,8 @@ export interface IUserMessageEvent extends IAgentEventBase {
35
35
  type: 'user-message';
36
36
  content: TAgentUserMessage['content'];
37
37
  providerOptions?: TAgentUserMessage['providerOptions'];
38
+ /** Set when a running generation took the message in from its pending input. */
39
+ inputId?: string;
38
40
  }
39
41
 
40
42
  export interface IAssistantMessageEvent extends IAgentEventBase {
@@ -106,6 +108,11 @@ export interface IGenerationOutcomeEvent extends IAgentEventBase {
106
108
  generationId: string;
107
109
  outcome: TAgentGenerationOutcome;
108
110
  reason?: string;
111
+ /**
112
+ * Set on an `interrupted` outcome whose owner stopped the generation: what its model produced
113
+ * stays in the model context.
114
+ */
115
+ stopped?: boolean;
109
116
  }
110
117
 
111
118
  export interface IToolExecutionIntentEvent extends IAgentEventBase {