@modelprofile.com/flexharness 4.0.2 → 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 +14 -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 +33 -2
- package/dist_ts/interfaces.d.ts +1 -0
- 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 +2 -2
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +33 -1
- package/ts/interfaces.ts +3 -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';
|
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
|
@@ -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);
|
|
@@ -5667,6 +5671,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
5667
5671
|
part.status = status === 'completed' ? 'completed' : 'cancelled';
|
|
5668
5672
|
} else if (part.type === 'tool' && part.status === 'running') {
|
|
5669
5673
|
part.status = status === 'cancelled' ? 'cancelled' : 'failed';
|
|
5674
|
+
delete part.output;
|
|
5670
5675
|
part.error = status === 'cancelled'
|
|
5671
5676
|
? 'Tool execution was cancelled.'
|
|
5672
5677
|
: 'Tool execution ended without a terminal event.';
|
|
@@ -6928,6 +6933,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6928
6933
|
part.output = output!;
|
|
6929
6934
|
} else {
|
|
6930
6935
|
part.status = 'failed';
|
|
6936
|
+
delete part.output;
|
|
6931
6937
|
part.error = projectedError!.message;
|
|
6932
6938
|
}
|
|
6933
6939
|
this.emitPartEvent(run, 'part.completed', part);
|
|
@@ -6936,6 +6942,31 @@ export class FlexHarness<TScope = unknown> {
|
|
|
6936
6942
|
}
|
|
6937
6943
|
}
|
|
6938
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
|
+
|
|
6939
6970
|
private callbackRun(state: IStorageState, sessionId: string): IActiveRun | undefined {
|
|
6940
6971
|
const run = state.activeRuns.get(sessionId);
|
|
6941
6972
|
return !run || run.callbacksClosed || run.callbackError ? undefined : run;
|
|
@@ -8100,6 +8131,7 @@ export class FlexHarness<TScope = unknown> {
|
|
|
8100
8131
|
onReasoningDelta: (id, delta) => this.onReasoningDelta(state, sessionId, id, delta),
|
|
8101
8132
|
onReasoningEnd: (id, text) => this.onReasoningEnd(state, sessionId, id, text),
|
|
8102
8133
|
onToolCallStart: (event) => this.onToolStart(state, sessionId, event),
|
|
8134
|
+
onToolCallUpdate: (event) => this.onToolUpdate(state, sessionId, event),
|
|
8103
8135
|
onToolCallFinish: (event) => this.onToolFinish(state, sessionId, event),
|
|
8104
8136
|
};
|
|
8105
8137
|
stored.agentSession = await this.withCompactorContext(
|
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];
|