@modelprofile.com/flexharness 4.0.1 → 4.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 +23 -0
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexharness.d.ts +1 -0
- package/dist_ts/classes.flexharness.js +35 -4
- package/dist_ts/interfaces.d.ts +6 -1
- package/dist_ts/interfaces.js +1 -1
- package/dist_ts/plugins.d.ts +1 -1
- package/package.json +2 -2
- package/readme.hints.md +1 -0
- package/readme.md +3 -3
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +43 -3
- package/ts/interfaces.ts +9 -0
- package/ts/plugins.ts +1 -0
package/dist_ts/interfaces.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export type TFlexAgentModelMessage = ReturnType<plugins.IAgentSession['getModelM
|
|
|
12
12
|
export type TFlexAgentToolSet = NonNullable<TFlexAgentSessionOptions['tools']>;
|
|
13
13
|
export type TFlexAgentProviderOptions = TFlexAgentSessionOptions['providerOptions'];
|
|
14
14
|
export type TFlexAgentCacheSetting = TFlexAgentSessionOptions['cache'];
|
|
15
|
+
export type TFlexAgentToolCallUpdateEvent = Parameters<NonNullable<TFlexAgentSessionOptions['onToolCallUpdate']>>[0];
|
|
15
16
|
export type TFlexAgentToolCallFinishEvent = Parameters<NonNullable<TFlexAgentSessionOptions['onToolCallFinish']>>[0];
|
|
16
17
|
export interface IFlexTextPromptPart {
|
|
17
18
|
type: 'text';
|
|
@@ -441,6 +442,10 @@ export interface IFlexPermissionSnapshot {
|
|
|
441
442
|
}
|
|
442
443
|
export declare const FLEX_PROJECT_MANAGEMENT_SCHEMA_VERSION: 1;
|
|
443
444
|
export declare const FLEX_SESSION_GENERATION_ID_MAX_BYTES = 128;
|
|
445
|
+
export interface IFlexSessionGeneration {
|
|
446
|
+
sessionGenerationId: string;
|
|
447
|
+
sessionGenerationSequence: number;
|
|
448
|
+
}
|
|
444
449
|
export declare const FLEX_PROJECT_MANAGEMENT_LIMITS: Readonly<{
|
|
445
450
|
maxGoalBytes: number;
|
|
446
451
|
maxScratchpadBytes: number;
|
|
@@ -485,7 +490,7 @@ export interface IFlexProjectManagementWriteContext {
|
|
|
485
490
|
toolCallId?: string;
|
|
486
491
|
}
|
|
487
492
|
export interface IFlexProjectManagementStore {
|
|
488
|
-
load(storageKey: string, sessionId: string): Promise<TFlexProjectManagementRecord | undefined>;
|
|
493
|
+
load(storageKey: string, sessionId: string, sessionGeneration?: Readonly<IFlexSessionGeneration>): Promise<TFlexProjectManagementRecord | undefined>;
|
|
489
494
|
save(storageKey: string, sessionId: string, snapshot: IFlexProjectManagementSnapshot, expectedRevision: number, writeContext: IFlexProjectManagementWriteContext): Promise<void>;
|
|
490
495
|
tombstoneSession(storageKey: string, sessionId: string, tombstone: IFlexProjectManagementTombstone, expectedRevision: number): Promise<void>;
|
|
491
496
|
purgeNamespace(storageKey: string): Promise<void>;
|
package/dist_ts/interfaces.js
CHANGED
|
@@ -26,4 +26,4 @@ export const FLEX_REVERSION_MAX_AFFECTED_WORKSPACES = 64;
|
|
|
26
26
|
export const FLEX_REVERSION_WORKSPACE_ID_MAX_BYTES = 512;
|
|
27
27
|
export const FLEX_REVERSION_WORKSPACE_LABEL_MAX_BYTES = 2048;
|
|
28
28
|
export const FLEX_REVERSION_REASON_CODE_MAX_BYTES = 128;
|
|
29
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
29
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJmYWNlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2ludGVyZmFjZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBNmpCQSxNQUFNLENBQUMsTUFBTSxzQ0FBc0MsR0FBRyxDQUFVLENBQUM7QUFDakUsTUFBTSxDQUFDLE1BQU0sb0NBQW9DLEdBQUcsR0FBRyxDQUFDO0FBT3hELE1BQU0sQ0FBQyxNQUFNLDhCQUE4QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDMUQsWUFBWSxFQUFFLENBQUMsR0FBRyxJQUFJO0lBQ3RCLGtCQUFrQixFQUFFLEdBQUcsR0FBRyxJQUFJO0lBQzlCLG1CQUFtQixFQUFFLENBQUMsR0FBRyxJQUFJO0lBQzdCLGNBQWMsRUFBRSxHQUFHO0lBQ25CLFFBQVEsRUFBRSxHQUFHO0lBQ2IsYUFBYSxFQUFFLElBQUk7SUFDbkIsZ0JBQWdCLEVBQUUsSUFBSSxHQUFHLElBQUk7Q0FDOUIsQ0FBQyxDQUFDO0FBMExILE1BQU0sQ0FBQyxNQUFNLDZCQUE2QixHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDekQsaUJBQWlCLEVBQUUsR0FBRztJQUN0QixXQUFXLEVBQUUsR0FBRztJQUNoQixpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLDJCQUEyQixFQUFFLElBQUk7Q0FDbEMsQ0FBQyxDQUFDO0FBRUgsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQztJQUN6RCxpQkFBaUIsRUFBRSxJQUFJO0lBQ3ZCLFdBQVcsRUFBRSxJQUFJO0lBQ2pCLGlCQUFpQixFQUFFLE1BQU07SUFDekIsMkJBQTJCLEVBQUUsTUFBTTtDQUNwQyxDQUFDLENBQUM7QUFFSCxNQUFNLENBQUMsTUFBTSxrQ0FBa0MsR0FBRyxHQUFHLEdBQUcsSUFBSSxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLHNDQUFzQyxHQUFHLEVBQUUsQ0FBQztBQUN6RCxNQUFNLENBQUMsTUFBTSxxQ0FBcUMsR0FBRyxHQUFHLENBQUM7QUFDekQsTUFBTSxDQUFDLE1BQU0sd0NBQXdDLEdBQUcsSUFBSSxDQUFDO0FBQzdELE1BQU0sQ0FBQyxNQUFNLG9DQUFvQyxHQUFHLEdBQUcsQ0FBQyJ9
|
package/dist_ts/plugins.d.ts
CHANGED
|
@@ -5,4 +5,4 @@ import * as path from 'node:path';
|
|
|
5
5
|
export { AsyncLocalStorage, crypto, fs, path };
|
|
6
6
|
import { AgentEventStoreConflictError, AgentSession, buildModelMessages, ToolJobStoreConflictError, createAgentEvent, filterModelVisibleAgentEvents, getAgentGenerationTransactions, modelMessagesToAgentEvents, tool, validateAgentEventArchiveV2, validateAgentEventSnapshotV2, z } from '@push.rocks/smartagent';
|
|
7
7
|
export { AgentEventStoreConflictError, AgentSession, buildModelMessages, ToolJobStoreConflictError, createAgentEvent, filterModelVisibleAgentEvents, getAgentGenerationTransactions, modelMessagesToAgentEvents, tool, validateAgentEventArchiveV2, validateAgentEventSnapshotV2, z, };
|
|
8
|
-
export type { IAgentEventArchiveV2, IAgentContextCompactionOptions, IAgentEventSnapshotV2, IAgentEventStoreV2, IAgentGenerateResult, IAgentGenerationHandle, IAgentGenerationLease, IAgentRunResult, IAgentSession, IAgentSessionOptions, IAgentRuntimeEventPayload, IGenerationBegunEvent, IGenerationExecutionCompletedEvent, IGenerationExecutionStartedEvent, IGenerationOutcomeEvent, IToolExecutionContext, IToolExecutionIntentEvent, IToolJobSnapshot, IToolJobState, IToolJobStore, TAgentContextBuilder, TAgentContextCompactor, TAgentEvent, TAgentGenerationOutcome, TAgentToolCallFinishEvent, TAgentToolExecutionReconciliationOptions, } from '@push.rocks/smartagent';
|
|
8
|
+
export type { IAgentEventArchiveV2, IAgentContextCompactionOptions, IAgentEventSnapshotV2, IAgentEventStoreV2, IAgentGenerateResult, IAgentGenerationHandle, IAgentGenerationLease, IAgentRunResult, IAgentSession, IAgentSessionOptions, IAgentToolCallUpdateEvent, IAgentRuntimeEventPayload, IGenerationBegunEvent, IGenerationExecutionCompletedEvent, IGenerationExecutionStartedEvent, IGenerationOutcomeEvent, IToolExecutionContext, IToolExecutionIntentEvent, IToolJobSnapshot, IToolJobState, IToolJobStore, TAgentContextBuilder, TAgentContextCompactor, TAgentEvent, TAgentGenerationOutcome, TAgentToolCallFinishEvent, TAgentToolExecutionReconciliationOptions, } from '@push.rocks/smartagent';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modelprofile.com/flexharness",
|
|
3
|
-
"version": "4.0
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Provider-neutral model-session runtime with durable history, permissions, typed events, and pluggable local or remote tool execution.",
|
|
6
6
|
"main": "dist_ts/index.js",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"node": ">=24"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@push.rocks/smartagent": "^
|
|
25
|
+
"@push.rocks/smartagent": "^5.0.0",
|
|
26
26
|
"@types/json-schema": "7.0.15"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
package/readme.hints.md
CHANGED
|
@@ -38,6 +38,7 @@ Implementation findings for flexharness.
|
|
|
38
38
|
## Tool output boundary
|
|
39
39
|
|
|
40
40
|
- Every tool `execute` result and every async-iterable yield is converted to bounded JSON before SmartAgent observes it. Thrown errors and iterator failures are not converted or swallowed.
|
|
41
|
+
- SmartAgent preliminary tool outputs mutate only the run-local running tool part and emit cumulative `part.updated` snapshots. Terminal success replaces them with the authoritative final output; failure, cancellation, and callback overflow remove them before persistence.
|
|
41
42
|
- JSON byte limits are propagated through traversal. Large strings never enter normalized output, and array/object traversal stops once the remaining allowance is reserved for deterministic truncation metadata.
|
|
42
43
|
- Model callbacks use bounded synchronous run-local parts. Adjacent text/reasoning deltas coalesce; no per-delta snapshot is written. Callback event, byte, or part overflow aborts internally and is classified as failure, not owner cancellation.
|
|
43
44
|
|
package/readme.md
CHANGED
|
@@ -241,7 +241,7 @@ Public writes use `{ actor: 'application' }`. Tool writes use `{ actor: 'agent',
|
|
|
241
241
|
|
|
242
242
|
`FLEX_PROJECT_MANAGEMENT_LIMITS` exports the hard UTF-8 and aggregate limits: goal 8 KiB, scratchpad 128 KiB, task content 8 KiB, task ID 512 bytes, title 2048 bytes, 512 tasks, and a 1 MiB serialized snapshot. The aggregate bound leaves room for worst-case JSON escaping of a controller-valid scratchpad. Loaded snapshots reject extra fields, duplicate IDs, invalid status/priority/timestamps, non-JSON data, wrong schema/revision, and every exceeded bound before use.
|
|
243
243
|
|
|
244
|
-
`IFlexProjectManagementStore` is exact per `(storageKey, sessionId)`: `load`, CAS `save`, CAS `tombstoneSession`, and `purgeNamespace` must not collapse multiple sessions or storage namespaces. `load()` returns `TFlexProjectManagementRecord | undefined
|
|
244
|
+
`IFlexProjectManagementStore` is exact per `(storageKey, sessionId)`: `load`, CAS `save`, CAS `tombstoneSession`, and `purgeNamespace` must not collapse multiple sessions or storage namespaces. `load()` returns `TFlexProjectManagementRecord | undefined` and receives the current session generation as an optional third argument; FlexHarness always supplies it, while two-argument callers and stores remain compatible. Same-generation live saves use normal revision CAS, and a same-generation tombstone permanently rejects later live saves. A higher `sessionGenerationSequence` with a different strong `sessionGenerationId` may replace only an older tombstone using expected revision `0`; it cannot replace a live record. This resets the PM revision for a recreated core session while stale saves and tombstones from older generations remain fenced. Deleting a recreated session that made no PM writes still replaces the prior-generation tombstone with a revision-1 tombstone for the new generation.
|
|
245
245
|
|
|
246
246
|
Every newly created core session exposes and persists a strong random `sessionGenerationId` plus its monotonic `sessionGenerationSequence`. A legacy scope session without those fields is assigned a deterministic bounded ID derived from its immutable `storageKey`, `sessionId`, and `createdAt`; FlexHarness persists the repaired scope snapshot before accepting work. Grouped core deletion tombstones retain both fields after live metadata is removed.
|
|
247
247
|
|
|
@@ -632,7 +632,7 @@ FlexHarness wraps every provided tool `execute` method before SmartAgent receive
|
|
|
632
632
|
|
|
633
633
|
`toolOutputLimits` in the complete setup above bounds traversal depth and encoded bytes. The normalizer enforces its byte allowance incrementally: oversized strings are replaced before entering output, and arrays/objects stop reading entries once only truncation metadata fits.
|
|
634
634
|
|
|
635
|
-
Streaming callbacks use run-local synchronous state rather than one persistence promise per delta. Adjacent text and reasoning deltas coalesce. `callbackLimits` bounds callback events, accumulated output bytes, and part count; overflow aborts internally with `FlexHarnessCallbackOverflowError` and the turn is recorded as failed. Reservation and terminal finalization are the normal persistence checkpoints, with permission state changes as explicit additional checkpoints.
|
|
635
|
+
Streaming callbacks use run-local synchronous state rather than one persistence promise per delta. Adjacent text and reasoning deltas coalesce. Preliminary async-iterable tool outputs appear as bounded cumulative `part.updated` snapshots while the tool remains `running`; only the authoritative `part.completed` output enters the terminal projection, and failed or interrupted tools discard their preliminary output. `callbackLimits` bounds callback events, accumulated output bytes, and part count; overflow aborts internally with `FlexHarnessCallbackOverflowError` and the turn is recorded as failed. Reservation and terminal finalization are the normal persistence checkpoints, with permission state changes as explicit additional checkpoints.
|
|
636
636
|
|
|
637
637
|
Model resolver, tool provider, AgentSession, tool execution, tool callback, tool cleanup, and run-persistence failures cross an untrusted error boundary. By default they become a fixed immutable `FlexHarnessExternalError` before completion rejection, persistence, events, or detached-cleanup reporting. Raw external messages and aggregate members are not retained. A failed `onToolCallFinish` callback stores and accounts for only the bounded projected message; it does not otherwise reject completion, although exceeding the configured callback limits still fails the run. Scope resolution and the initial store load happen before a run exists and remain outside this boundary.
|
|
638
638
|
|
|
@@ -685,7 +685,7 @@ const unsubscribe = harness.subscribe((event) => {
|
|
|
685
685
|
unsubscribe();
|
|
686
686
|
```
|
|
687
687
|
|
|
688
|
-
Events are discriminated, sequenced, deeply immutable snapshots. Listener exceptions are isolated from runs and other listeners. Every accepted queue entry emits `prompt.queued` and exactly one `prompt.finished`. Durable promotion additionally emits `prompt.started`, and actual model preparation emits `prompt.running`; cancellation or failure can omit either intermediate event. Existing durable run/message terminal events precede `prompt.finished`. Every callback-backed streamed text part emits exactly one `part.completed` event before the corresponding `run.finished` event. Every `part.started`, `part.delta`, `part.updated`, and `part.completed` event carries zero-based `messageIndex` and `partIndex` coordinates from the session's authoritative message and part sequences. `part.updated` is cumulative
|
|
688
|
+
Events are discriminated, sequenced, deeply immutable snapshots. Listener exceptions are isolated from runs and other listeners. Every accepted queue entry emits `prompt.queued` and exactly one `prompt.finished`. Durable promotion additionally emits `prompt.started`, and actual model preparation emits `prompt.running`; cancellation or failure can omit either intermediate event. Existing durable run/message terminal events precede `prompt.finished`. Every callback-backed streamed text part emits exactly one `part.completed` event before the corresponding `run.finished` event. Every `part.started`, `part.delta`, `part.updated`, and `part.completed` event carries zero-based `messageIndex` and `partIndex` coordinates from the session's authoritative message and part sequences. `part.updated` is a cumulative replacement snapshot for running tool output or metadata, not a text delta. `session.history.changed` carries `direction: 'undo' | 'redo' | 'branch'`; `runId` is present for undo and redo. Events contain public IDs and snapshots only; they do not expose prompt payloads, the resolved scope object, storage key, model object, provider options, or raw storage key.
|
|
689
689
|
|
|
690
690
|
## Stores
|
|
691
691
|
|
package/ts/00_commitinfo_data.ts
CHANGED
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@modelprofile.com/flexharness',
|
|
6
|
-
version: '4.0
|
|
6
|
+
version: '4.1.0',
|
|
7
7
|
description: 'Provider-neutral model-session runtime with durable history, permissions, typed events, and pluggable local or remote tool execution.'
|
|
8
8
|
}
|
|
@@ -96,6 +96,7 @@ import type {
|
|
|
96
96
|
IFlexUsage,
|
|
97
97
|
IJsonObject,
|
|
98
98
|
TFlexAgentRunResult,
|
|
99
|
+
TFlexAgentToolCallUpdateEvent,
|
|
99
100
|
TFlexAgentToolCallFinishEvent,
|
|
100
101
|
TFlexAgentToolSet,
|
|
101
102
|
TFlexAttachmentSource,
|
|
@@ -556,7 +557,7 @@ function requireSessionGeneration(
|
|
|
556
557
|
function isAsyncIterable(value: unknown): value is AsyncIterable<unknown> {
|
|
557
558
|
return Boolean(
|
|
558
559
|
value
|
|
559
|
-
&& typeof value === 'object'
|
|
560
|
+
&& (typeof value === 'object' || typeof value === 'function')
|
|
560
561
|
&& typeof (value as { [Symbol.asyncIterator]?: unknown })[Symbol.asyncIterator] === 'function',
|
|
561
562
|
);
|
|
562
563
|
}
|
|
@@ -601,6 +602,9 @@ function wrapToolSet(
|
|
|
601
602
|
return Promise.resolve(output).then(
|
|
602
603
|
(value) => {
|
|
603
604
|
try {
|
|
605
|
+
if (isAsyncIterable(value)) {
|
|
606
|
+
return normalizeAsyncIterable(value, limits, projectError);
|
|
607
|
+
}
|
|
604
608
|
return normalizeJsonValue(value, limits);
|
|
605
609
|
} catch (error) {
|
|
606
610
|
throw projectError(error);
|
|
@@ -4391,7 +4395,11 @@ export class FlexHarness<TScope = unknown> {
|
|
|
4391
4395
|
): Promise<IFlexProjectManagementSnapshot> {
|
|
4392
4396
|
const store = this.stores.projectManagement;
|
|
4393
4397
|
const generation = requireSessionGeneration(stored.session);
|
|
4394
|
-
const record = await store.load(
|
|
4398
|
+
const record = await store.load(
|
|
4399
|
+
state.storageKey,
|
|
4400
|
+
stored.session.sessionId,
|
|
4401
|
+
Object.freeze({ ...generation }),
|
|
4402
|
+
);
|
|
4395
4403
|
if (record === undefined) {
|
|
4396
4404
|
return createEmptyFlexProjectManagementSnapshot(
|
|
4397
4405
|
generation.sessionGenerationId,
|
|
@@ -5663,6 +5671,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5663
5671
|
part.status = status === 'completed' ? 'completed' : 'cancelled';
|
|
5664
5672
|
} else if (part.type === 'tool' && part.status === 'running') {
|
|
5665
5673
|
part.status = status === 'cancelled' ? 'cancelled' : 'failed';
|
|
5674
|
+
delete part.output;
|
|
5666
5675
|
part.error = status === 'cancelled'
|
|
5667
5676
|
? 'Tool execution was cancelled.'
|
|
5668
5677
|
: 'Tool execution ended without a terminal event.';
|
|
@@ -6924,6 +6933,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6924
6933
|
part.output = output!;
|
|
6925
6934
|
} else {
|
|
6926
6935
|
part.status = 'failed';
|
|
6936
|
+
delete part.output;
|
|
6927
6937
|
part.error = projectedError!.message;
|
|
6928
6938
|
}
|
|
6929
6939
|
this.emitPartEvent(run, 'part.completed', part);
|
|
@@ -6932,6 +6942,31 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6932
6942
|
}
|
|
6933
6943
|
}
|
|
6934
6944
|
|
|
6945
|
+
private onToolUpdate(
|
|
6946
|
+
state: IStorageState,
|
|
6947
|
+
sessionId: string,
|
|
6948
|
+
event: TFlexAgentToolCallUpdateEvent,
|
|
6949
|
+
): void {
|
|
6950
|
+
let run = this.callbackRun(state, sessionId);
|
|
6951
|
+
if (!run) return;
|
|
6952
|
+
if (!run.toolPartIds.has(event.toolCallId)) {
|
|
6953
|
+
this.onToolStart(state, sessionId, event);
|
|
6954
|
+
run = this.callbackRun(state, sessionId);
|
|
6955
|
+
if (!run) return;
|
|
6956
|
+
}
|
|
6957
|
+
const partId = run.toolPartIds.get(event.toolCallId);
|
|
6958
|
+
const part = run.callbackParts.find((entry) => entry.partId === partId && entry.type === 'tool');
|
|
6959
|
+
if (!part || part.type !== 'tool' || part.status !== 'running') return;
|
|
6960
|
+
try {
|
|
6961
|
+
const output = normalizeJsonValue(event.output, this.toolOutputLimits);
|
|
6962
|
+
if (!this.reserveCallbackCapacity(run, 1, jsonBytes(output), 0)) return;
|
|
6963
|
+
part.output = output;
|
|
6964
|
+
this.emitPartEvent(run, 'part.updated', part);
|
|
6965
|
+
} catch (error) {
|
|
6966
|
+
this.failCallback(run, this.projectExternalError(run, error, 'toolCallback'));
|
|
6967
|
+
}
|
|
6968
|
+
}
|
|
6969
|
+
|
|
6935
6970
|
private callbackRun(state: IStorageState, sessionId: string): IActiveRun | undefined {
|
|
6936
6971
|
const run = state.activeRuns.get(sessionId);
|
|
6937
6972
|
return !run || run.callbacksClosed || run.callbackError ? undefined : run;
|
|
@@ -8096,6 +8131,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
8096
8131
|
onReasoningDelta: (id, delta) => this.onReasoningDelta(state, sessionId, id, delta),
|
|
8097
8132
|
onReasoningEnd: (id, text) => this.onReasoningEnd(state, sessionId, id, text),
|
|
8098
8133
|
onToolCallStart: (event) => this.onToolStart(state, sessionId, event),
|
|
8134
|
+
onToolCallUpdate: (event) => this.onToolUpdate(state, sessionId, event),
|
|
8099
8135
|
onToolCallFinish: (event) => this.onToolFinish(state, sessionId, event),
|
|
8100
8136
|
};
|
|
8101
8137
|
stored.agentSession = await this.withCompactorContext(
|
|
@@ -8795,7 +8831,11 @@ export class FlexHarness<TScope = unknown> {
|
|
|
8795
8831
|
const generation = requireSessionGeneration(sessionTombstone);
|
|
8796
8832
|
let lastConflict: FlexHarnessStoreConflictError | undefined;
|
|
8797
8833
|
for (let attempt = 0; attempt <= maxProjectManagementTombstoneConflicts; attempt++) {
|
|
8798
|
-
const current = await store.load(
|
|
8834
|
+
const current = await store.load(
|
|
8835
|
+
storageKey,
|
|
8836
|
+
sessionId,
|
|
8837
|
+
Object.freeze({ ...generation }),
|
|
8838
|
+
);
|
|
8799
8839
|
if (current !== undefined) {
|
|
8800
8840
|
assertFlexProjectManagementRecord(current);
|
|
8801
8841
|
if (current.sessionGenerationId === generation.sessionGenerationId) {
|
package/ts/interfaces.ts
CHANGED
|
@@ -16,6 +16,9 @@ export type TFlexAgentModelMessage = ReturnType<plugins.IAgentSession['getModelM
|
|
|
16
16
|
export type TFlexAgentToolSet = NonNullable<TFlexAgentSessionOptions['tools']>;
|
|
17
17
|
export type TFlexAgentProviderOptions = TFlexAgentSessionOptions['providerOptions'];
|
|
18
18
|
export type TFlexAgentCacheSetting = TFlexAgentSessionOptions['cache'];
|
|
19
|
+
export type TFlexAgentToolCallUpdateEvent = Parameters<
|
|
20
|
+
NonNullable<TFlexAgentSessionOptions['onToolCallUpdate']>
|
|
21
|
+
>[0];
|
|
19
22
|
export type TFlexAgentToolCallFinishEvent = Parameters<
|
|
20
23
|
NonNullable<TFlexAgentSessionOptions['onToolCallFinish']>
|
|
21
24
|
>[0];
|
|
@@ -571,6 +574,11 @@ export interface IFlexPermissionSnapshot {
|
|
|
571
574
|
export const FLEX_PROJECT_MANAGEMENT_SCHEMA_VERSION = 1 as const;
|
|
572
575
|
export const FLEX_SESSION_GENERATION_ID_MAX_BYTES = 128;
|
|
573
576
|
|
|
577
|
+
export interface IFlexSessionGeneration {
|
|
578
|
+
sessionGenerationId: string;
|
|
579
|
+
sessionGenerationSequence: number;
|
|
580
|
+
}
|
|
581
|
+
|
|
574
582
|
export const FLEX_PROJECT_MANAGEMENT_LIMITS = Object.freeze({
|
|
575
583
|
maxGoalBytes: 8 * 1024,
|
|
576
584
|
maxScratchpadBytes: 128 * 1024,
|
|
@@ -628,6 +636,7 @@ export interface IFlexProjectManagementStore {
|
|
|
628
636
|
load(
|
|
629
637
|
storageKey: string,
|
|
630
638
|
sessionId: string,
|
|
639
|
+
sessionGeneration?: Readonly<IFlexSessionGeneration>,
|
|
631
640
|
): Promise<TFlexProjectManagementRecord | undefined>;
|
|
632
641
|
save(
|
|
633
642
|
storageKey: string,
|