@modelprofile.com/flexharness 9.10.0 → 10.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/classes.flexharness.d.ts +2 -0
- package/dist_ts/classes.flexharness.js +101 -7
- package/dist_ts/classes.stores.js +11 -119
- package/dist_ts/errors.d.ts +7 -2
- package/dist_ts/errors.js +1 -1
- package/dist_ts/interfaces.d.ts +1 -0
- package/dist_ts/utils.harnessoptions.js +2 -1
- package/dist_ts/utils.storerules.d.ts +28 -0
- package/dist_ts/utils.storerules.js +107 -0
- package/dist_ts_chat_harness/classes.transcript.d.ts +88 -0
- package/dist_ts_chat_harness/classes.transcript.js +268 -0
- package/dist_ts_chat_harness/functions.intents.d.ts +62 -0
- package/dist_ts_chat_harness/functions.intents.js +96 -0
- package/dist_ts_chat_harness/functions.mapping.d.ts +33 -0
- package/dist_ts_chat_harness/functions.mapping.js +220 -0
- package/dist_ts_chat_harness/index.d.ts +3 -0
- package/dist_ts_chat_harness/index.js +4 -0
- package/dist_ts_chat_harness/plugins.d.ts +1 -0
- package/dist_ts_chat_harness/plugins.js +2 -0
- package/dist_ts_kvm/classes.browserkvm.js +3 -3
- package/dist_ts_kvm/plugins.d.ts +1 -1
- package/dist_ts_kvm/plugins.js +2 -2
- package/dist_ts_stores_nosqldb/classes.nosqldbstores.d.ts +31 -0
- package/dist_ts_stores_nosqldb/classes.nosqldbstores.js +312 -0
- package/dist_ts_stores_nosqldb/classes.recordstore.d.ts +110 -0
- package/dist_ts_stores_nosqldb/classes.recordstore.js +437 -0
- package/dist_ts_stores_nosqldb/index.d.ts +2 -0
- package/dist_ts_stores_nosqldb/index.js +3 -0
- package/dist_ts_stores_nosqldb/plugins.d.ts +7 -0
- package/dist_ts_stores_nosqldb/plugins.js +10 -0
- package/package.json +27 -7
- package/readme.md +14 -6
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/classes.flexharness.ts +102 -7
- package/ts/classes.stores.ts +28 -172
- package/ts/errors.ts +8 -2
- package/ts/interfaces.ts +1 -0
- package/ts/readme.md +14 -6
- package/ts/utils.harnessoptions.ts +1 -0
- package/ts/utils.storerules.ts +177 -0
- package/ts_chat_harness/classes.transcript.ts +365 -0
- package/ts_chat_harness/functions.intents.ts +169 -0
- package/ts_chat_harness/functions.mapping.ts +267 -0
- package/ts_chat_harness/index.ts +33 -0
- package/ts_chat_harness/plugins.ts +18 -0
- package/ts_chat_harness/readme.md +114 -0
- package/ts_kvm/classes.browserkvm.ts +2 -2
- package/ts_kvm/plugins.ts +1 -1
- package/ts_stores_nosqldb/classes.nosqldbstores.ts +465 -0
- package/ts_stores_nosqldb/classes.recordstore.ts +560 -0
- package/ts_stores_nosqldb/index.ts +9 -0
- package/ts_stores_nosqldb/plugins.ts +38 -0
- package/ts_stores_nosqldb/readme.md +53 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { FlexHarnessStoreConflictError, FlexHarnessStoreFormatError, FlexHarnessValidationError, } from './errors.js';
|
|
2
|
+
import { assertJsonSerializable, cloneSerializable } from './utils.json.js';
|
|
3
|
+
import { assertExactKeys, assertRecord } from './utils.storecodecs.js';
|
|
4
|
+
export function validateIdentifier(value, name) {
|
|
5
|
+
if (typeof value !== 'string' || !value.trim()) {
|
|
6
|
+
throw new FlexHarnessValidationError(`${name} must be a non-empty string.`);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export function validateExpectedRevision(expectedRevision) {
|
|
10
|
+
if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 0) {
|
|
11
|
+
throw new FlexHarnessValidationError('expectedRevision must be a non-negative integer.');
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export function validateProjectManagementWriteContext(writeContext) {
|
|
15
|
+
assertJsonSerializable(writeContext, '$writeContext');
|
|
16
|
+
assertRecord(writeContext, 'writeContext');
|
|
17
|
+
assertExactKeys(writeContext, ['actor', 'runId', 'agent', 'toolCallId'], 'writeContext');
|
|
18
|
+
if (writeContext.actor !== 'agent' && writeContext.actor !== 'application') {
|
|
19
|
+
throw new FlexHarnessValidationError('writeContext.actor must be agent or application.');
|
|
20
|
+
}
|
|
21
|
+
for (const key of ['runId', 'agent', 'toolCallId']) {
|
|
22
|
+
if (writeContext[key] !== undefined)
|
|
23
|
+
validateIdentifier(writeContext[key], `writeContext.${key}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export function validateSnapshotSave(snapshot, expectedRevision, validator) {
|
|
27
|
+
validator(snapshot);
|
|
28
|
+
validateExpectedRevision(expectedRevision);
|
|
29
|
+
if (snapshot.revision !== expectedRevision + 1) {
|
|
30
|
+
throw new FlexHarnessStoreFormatError(`Snapshot revision ${snapshot.revision} must equal expected revision ${expectedRevision} plus one.`);
|
|
31
|
+
}
|
|
32
|
+
return cloneSerializable(snapshot);
|
|
33
|
+
}
|
|
34
|
+
export function providerKey(storageKey, sessionId) {
|
|
35
|
+
validateIdentifier(storageKey, 'storageKey');
|
|
36
|
+
validateIdentifier(sessionId, 'sessionId');
|
|
37
|
+
return JSON.stringify([storageKey, sessionId]);
|
|
38
|
+
}
|
|
39
|
+
export function assertProjectionSession(snapshot, sessionId) {
|
|
40
|
+
for (const message of snapshot.messages) {
|
|
41
|
+
if (message.sessionId !== sessionId) {
|
|
42
|
+
throw new FlexHarnessStoreFormatError(`Projection message "${message.messageId}" does not belong to session "${sessionId}".`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
for (const terminal of snapshot.stagedTerminals) {
|
|
46
|
+
if (terminal.userMessage.sessionId !== sessionId
|
|
47
|
+
|| terminal.assistantMessage.sessionId !== sessionId) {
|
|
48
|
+
throw new FlexHarnessStoreFormatError(`Staged terminal "${terminal.runId}" does not belong to session "${sessionId}".`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function sameProjectManagementGeneration(left, right) {
|
|
53
|
+
return left.sessionGenerationId === right.sessionGenerationId
|
|
54
|
+
&& left.sessionGenerationSequence === right.sessionGenerationSequence;
|
|
55
|
+
}
|
|
56
|
+
function canInitializeProjectManagementGeneration(current, next, expectedRevision) {
|
|
57
|
+
return 'deletedAt' in current
|
|
58
|
+
&& expectedRevision === 0
|
|
59
|
+
&& next.sessionGenerationId !== current.sessionGenerationId
|
|
60
|
+
&& next.sessionGenerationSequence > current.sessionGenerationSequence;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Admits a live project-management save over the stored record: a CAS save within the stored
|
|
64
|
+
* generation, or a newer generation that replaces a tombstone at expected revision 0.
|
|
65
|
+
*/
|
|
66
|
+
export function assertProjectManagementSaveAdmitted(key, current, snapshot, expectedRevision) {
|
|
67
|
+
const actualRevision = current?.revision ?? 0;
|
|
68
|
+
if (current && !sameProjectManagementGeneration(current, snapshot)) {
|
|
69
|
+
if (!canInitializeProjectManagementGeneration(current, snapshot, expectedRevision)) {
|
|
70
|
+
throw new FlexHarnessStoreConflictError(key, expectedRevision, actualRevision);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
else if ((current && 'deletedAt' in current) || actualRevision !== expectedRevision) {
|
|
74
|
+
throw new FlexHarnessStoreConflictError(key, expectedRevision, actualRevision);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Admits a project-management tombstone over the stored record. Returns false when the same
|
|
79
|
+
* generation is already tombstoned, which makes a repeated cleanup idempotent.
|
|
80
|
+
*/
|
|
81
|
+
export function isProjectManagementTombstoneAdmitted(key, current, tombstone, expectedRevision) {
|
|
82
|
+
const actualRevision = current?.revision ?? 0;
|
|
83
|
+
if (current && sameProjectManagementGeneration(current, tombstone)) {
|
|
84
|
+
if ('deletedAt' in current)
|
|
85
|
+
return false;
|
|
86
|
+
if (actualRevision !== expectedRevision) {
|
|
87
|
+
throw new FlexHarnessStoreConflictError(key, expectedRevision, actualRevision);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
else if (current) {
|
|
91
|
+
if (!canInitializeProjectManagementGeneration(current, tombstone, expectedRevision)) {
|
|
92
|
+
throw new FlexHarnessStoreConflictError(key, expectedRevision, actualRevision);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else if (actualRevision !== expectedRevision) {
|
|
96
|
+
throw new FlexHarnessStoreConflictError(key, expectedRevision, actualRevision);
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
/** An archive is written once; repeating it with the same events is a no-op. */
|
|
101
|
+
export function assertSameArchiveEvents(existing, next) {
|
|
102
|
+
if (JSON.stringify(existing.events.map((event) => event.id))
|
|
103
|
+
!== JSON.stringify(next.events.map((event) => event.id))) {
|
|
104
|
+
throw new Error(`Archive "${next.archiveId}" already exists with different events.`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuc3RvcmVydWxlcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3V0aWxzLnN0b3JlcnVsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUNMLDZCQUE2QixFQUM3QiwyQkFBMkIsRUFDM0IsMEJBQTBCLEdBQzNCLE1BQU0sYUFBYSxDQUFDO0FBVXJCLE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzVFLE9BQU8sRUFBRSxlQUFlLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFpQnZFLE1BQU0sVUFBVSxrQkFBa0IsQ0FBQyxLQUFhLEVBQUUsSUFBWTtJQUM1RCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1FBQy9DLE1BQU0sSUFBSSwwQkFBMEIsQ0FBQyxHQUFHLElBQUksOEJBQThCLENBQUMsQ0FBQztJQUM5RSxDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSx3QkFBd0IsQ0FBQyxnQkFBd0I7SUFDL0QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxhQUFhLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxnQkFBZ0IsR0FBRyxDQUFDLEVBQUUsQ0FBQztRQUNwRSxNQUFNLElBQUksMEJBQTBCLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUMzRixDQUFDO0FBQ0gsQ0FBQztBQUVELE1BQU0sVUFBVSxxQ0FBcUMsQ0FDbkQsWUFBZ0Q7SUFFaEQsc0JBQXNCLENBQUMsWUFBWSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ3RELFlBQVksQ0FBQyxZQUFZLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFDM0MsZUFBZSxDQUFDLFlBQVksRUFBRSxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxFQUFFLFlBQVksQ0FBQyxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQ3pGLElBQUksWUFBWSxDQUFD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
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import type * as plugins from './plugins.js';
|
|
2
|
+
import type { IFlexMessage, IFlexPermissionRequest, IFlexProjectStateResult, IFlexSession, TFlexHarnessEvent } from '../dist_ts/interfaces.js';
|
|
3
|
+
export interface IFlexHarnessTranscriptOptions {
|
|
4
|
+
scopeId: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
}
|
|
7
|
+
/** What `load()` reads: the session's authoritative state, as the harness APIs return it. */
|
|
8
|
+
export interface IFlexHarnessTranscriptSnapshot {
|
|
9
|
+
/** `getMessages()` of the session. */
|
|
10
|
+
messages: readonly IFlexMessage[];
|
|
11
|
+
/** `listPendingPermissions()` of the session. */
|
|
12
|
+
permissions?: readonly IFlexPermissionRequest[];
|
|
13
|
+
/** `getSession()`; states whether a run is active or failed. */
|
|
14
|
+
session?: IFlexSession;
|
|
15
|
+
/** `getProjectState()`, when project management is enabled. */
|
|
16
|
+
project?: IFlexProjectStateResult;
|
|
17
|
+
}
|
|
18
|
+
/** The inputs of `dees-harness-chat`, as plain data the transcript does not share. */
|
|
19
|
+
export interface IFlexHarnessTranscriptView {
|
|
20
|
+
messages: plugins.IHarnessMessage[];
|
|
21
|
+
permissions: plugins.IHarnessPermissionRequest[];
|
|
22
|
+
/** FlexHarness asks no questions; always empty. */
|
|
23
|
+
questions: plugins.IHarnessQuestionRequest[];
|
|
24
|
+
status: plugins.IHarnessStatus;
|
|
25
|
+
usage: plugins.IHarnessUsage;
|
|
26
|
+
todos: plugins.IHarnessTodoItem[];
|
|
27
|
+
scratchpad?: plugins.IHarnessScratchpad;
|
|
28
|
+
}
|
|
29
|
+
/** Where an event stands in its harness instance's event stream, as the host received it. */
|
|
30
|
+
export interface IFlexHarnessEventDelivery {
|
|
31
|
+
/**
|
|
32
|
+
* The `sequence` of the event of the same harness instance the host received just before this
|
|
33
|
+
* one, of any session; `undefined` for the first event after `load()`. The host forwards every
|
|
34
|
+
* event of the instance in order, and calls `load()` after a gap or a reconnect.
|
|
35
|
+
*/
|
|
36
|
+
precedingSequence: number | undefined;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* What one event changed. Apply `deltas` with `applyDelta()` in order; when `messages` is true,
|
|
40
|
+
* assign `transcript.view().messages` instead, which already holds the deltas. `reload` means
|
|
41
|
+
* the transcript can no longer follow the session incrementally: read the session again and
|
|
42
|
+
* pass it to `load()`.
|
|
43
|
+
*/
|
|
44
|
+
export interface IFlexHarnessTranscriptChange {
|
|
45
|
+
messages: boolean;
|
|
46
|
+
deltas: plugins.THarnessStreamDelta[];
|
|
47
|
+
permissions: boolean;
|
|
48
|
+
status: boolean;
|
|
49
|
+
usage: boolean;
|
|
50
|
+
reload: boolean;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Follows one FlexHarness session and keeps the `dees-harness-chat` inputs for it. It is a pure
|
|
54
|
+
* reducer over the session's public messages and events: it imports no runtime code, so it runs
|
|
55
|
+
* in the browser beside the components as well as on the server beside the harness.
|
|
56
|
+
*/
|
|
57
|
+
export declare class FlexHarnessTranscript {
|
|
58
|
+
readonly scopeId: string;
|
|
59
|
+
readonly sessionId: string;
|
|
60
|
+
private flexMessages;
|
|
61
|
+
private readonly timings;
|
|
62
|
+
private readonly partBytes;
|
|
63
|
+
private readonly permissionRows;
|
|
64
|
+
private status;
|
|
65
|
+
private usage;
|
|
66
|
+
private todos;
|
|
67
|
+
private scratchpad?;
|
|
68
|
+
private runningQueueId?;
|
|
69
|
+
constructor(options: IFlexHarnessTranscriptOptions);
|
|
70
|
+
/** The queue entry whose run is running; a steer joins it. */
|
|
71
|
+
get activeQueueId(): string | undefined;
|
|
72
|
+
/** Replaces everything with the session's authoritative state. */
|
|
73
|
+
load(snapshot: IFlexHarnessTranscriptSnapshot): void;
|
|
74
|
+
/** Takes in the session's task list and scratchpad after `getProjectState()`. */
|
|
75
|
+
applyProjectState(project: IFlexProjectStateResult): void;
|
|
76
|
+
/** A copy of the component inputs; the transcript keeps its own objects. */
|
|
77
|
+
view(): IFlexHarnessTranscriptView;
|
|
78
|
+
/**
|
|
79
|
+
* Takes one event of the harness instance. An event that does not directly follow
|
|
80
|
+
* `delivery.precedingSequence` means events were lost, possibly of this session, so the change
|
|
81
|
+
* asks for a reload.
|
|
82
|
+
*/
|
|
83
|
+
applyEvent(event: TFlexHarnessEvent, delivery: IFlexHarnessEventDelivery): IFlexHarnessTranscriptChange;
|
|
84
|
+
private setStatus;
|
|
85
|
+
private upsertMessage;
|
|
86
|
+
private applyPartSnapshot;
|
|
87
|
+
private applyPartDelta;
|
|
88
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { flexMessageToHarnessRows, flexPartRowId, flexPartTimingKey, flexPermissionToHarness, flexProjectToHarnessScratchpad, flexProjectToHarnessTodos, flexSessionToHarnessStatus, flexToolPartToHarness, flexUsageToHarness, } from './functions.mapping.js';
|
|
2
|
+
const utf8 = new TextEncoder();
|
|
3
|
+
/** UTF-8 bytes `delta` adds to `text`, counted the way FlexHarness counts them. */
|
|
4
|
+
function appendedUtf8Bytes(text, delta) {
|
|
5
|
+
const trailing = text.charCodeAt(text.length - 1);
|
|
6
|
+
const leading = delta.charCodeAt(0);
|
|
7
|
+
const joinsSurrogatePair = trailing >= 0xd800 && trailing <= 0xdbff
|
|
8
|
+
&& leading >= 0xdc00 && leading <= 0xdfff;
|
|
9
|
+
return utf8.encode(delta).length - (joinsSurrogatePair ? 2 : 0);
|
|
10
|
+
}
|
|
11
|
+
function sumUsage(total, usage) {
|
|
12
|
+
const sum = (key) => (total[key] ?? 0) + (usage[key] ?? 0);
|
|
13
|
+
return {
|
|
14
|
+
inputTokens: sum('inputTokens'),
|
|
15
|
+
outputTokens: sum('outputTokens'),
|
|
16
|
+
totalTokens: sum('totalTokens'),
|
|
17
|
+
cacheReadTokens: sum('cacheReadTokens'),
|
|
18
|
+
cacheWriteTokens: sum('cacheWriteTokens'),
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const noChange = () => ({
|
|
22
|
+
messages: false,
|
|
23
|
+
deltas: [],
|
|
24
|
+
permissions: false,
|
|
25
|
+
status: false,
|
|
26
|
+
usage: false,
|
|
27
|
+
reload: false,
|
|
28
|
+
});
|
|
29
|
+
/**
|
|
30
|
+
* Follows one FlexHarness session and keeps the `dees-harness-chat` inputs for it. It is a pure
|
|
31
|
+
* reducer over the session's public messages and events: it imports no runtime code, so it runs
|
|
32
|
+
* in the browser beside the components as well as on the server beside the harness.
|
|
33
|
+
*/
|
|
34
|
+
export class FlexHarnessTranscript {
|
|
35
|
+
scopeId;
|
|
36
|
+
sessionId;
|
|
37
|
+
flexMessages = [];
|
|
38
|
+
timings = new Map();
|
|
39
|
+
partBytes = new Map();
|
|
40
|
+
permissionRows = new Map();
|
|
41
|
+
status = { type: 'idle' };
|
|
42
|
+
usage = {};
|
|
43
|
+
todos = [];
|
|
44
|
+
scratchpad;
|
|
45
|
+
runningQueueId;
|
|
46
|
+
constructor(options) {
|
|
47
|
+
this.scopeId = options.scopeId;
|
|
48
|
+
this.sessionId = options.sessionId;
|
|
49
|
+
}
|
|
50
|
+
/** The queue entry whose run is running; a steer joins it. */
|
|
51
|
+
get activeQueueId() {
|
|
52
|
+
return this.runningQueueId;
|
|
53
|
+
}
|
|
54
|
+
/** Replaces everything with the session's authoritative state. */
|
|
55
|
+
load(snapshot) {
|
|
56
|
+
this.flexMessages = [];
|
|
57
|
+
this.todos = [];
|
|
58
|
+
this.scratchpad = undefined;
|
|
59
|
+
this.runningQueueId = undefined;
|
|
60
|
+
this.timings.clear();
|
|
61
|
+
this.partBytes.clear();
|
|
62
|
+
for (const message of snapshot.messages)
|
|
63
|
+
this.upsertMessage(message);
|
|
64
|
+
this.permissionRows.clear();
|
|
65
|
+
for (const request of snapshot.permissions ?? []) {
|
|
66
|
+
this.permissionRows.set(request.permissionId, flexPermissionToHarness(request));
|
|
67
|
+
}
|
|
68
|
+
this.status = snapshot.session ? flexSessionToHarnessStatus(snapshot.session) : { type: 'idle' };
|
|
69
|
+
this.usage = this.flexMessages.reduce((total, message) => message.usage ? sumUsage(total, flexUsageToHarness(message.usage)) : total, {});
|
|
70
|
+
if (snapshot.project)
|
|
71
|
+
this.applyProjectState(snapshot.project);
|
|
72
|
+
}
|
|
73
|
+
/** Takes in the session's task list and scratchpad after `getProjectState()`. */
|
|
74
|
+
applyProjectState(project) {
|
|
75
|
+
this.todos = flexProjectToHarnessTodos(project);
|
|
76
|
+
this.scratchpad = flexProjectToHarnessScratchpad(this.sessionId, project);
|
|
77
|
+
}
|
|
78
|
+
/** A copy of the component inputs; the transcript keeps its own objects. */
|
|
79
|
+
view() {
|
|
80
|
+
return structuredClone({
|
|
81
|
+
messages: this.flexMessages.flatMap((message, index) => flexMessageToHarnessRows(message, index, this.timings)),
|
|
82
|
+
permissions: [...this.permissionRows.values()],
|
|
83
|
+
questions: [],
|
|
84
|
+
status: this.status,
|
|
85
|
+
usage: this.usage,
|
|
86
|
+
todos: this.todos,
|
|
87
|
+
...(this.scratchpad === undefined ? {} : { scratchpad: this.scratchpad }),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Takes one event of the harness instance. An event that does not directly follow
|
|
92
|
+
* `delivery.precedingSequence` means events were lost, possibly of this session, so the change
|
|
93
|
+
* asks for a reload.
|
|
94
|
+
*/
|
|
95
|
+
applyEvent(event, delivery) {
|
|
96
|
+
const change = noChange();
|
|
97
|
+
if (delivery.precedingSequence !== undefined
|
|
98
|
+
&& event.sequence !== delivery.precedingSequence + 1) {
|
|
99
|
+
change.reload = true;
|
|
100
|
+
return change;
|
|
101
|
+
}
|
|
102
|
+
if (event.scopeId !== this.scopeId || event.sessionId !== this.sessionId)
|
|
103
|
+
return change;
|
|
104
|
+
const timestamp = Date.parse(event.timestamp);
|
|
105
|
+
switch (event.type) {
|
|
106
|
+
case 'session.created':
|
|
107
|
+
case 'session.updated':
|
|
108
|
+
this.setStatus(change, flexSessionToHarnessStatus(event.session));
|
|
109
|
+
break;
|
|
110
|
+
case 'session.deleted':
|
|
111
|
+
this.load({ messages: [] });
|
|
112
|
+
change.messages = change.permissions = change.status = change.usage = true;
|
|
113
|
+
break;
|
|
114
|
+
case 'run.started':
|
|
115
|
+
this.setStatus(change, { type: 'busy' });
|
|
116
|
+
break;
|
|
117
|
+
case 'message.created':
|
|
118
|
+
case 'message.updated':
|
|
119
|
+
this.upsertMessage(event.message);
|
|
120
|
+
change.messages = true;
|
|
121
|
+
break;
|
|
122
|
+
case 'part.started':
|
|
123
|
+
this.timings.set(flexPartTimingKey(event.messageId, event.partId), { startedAt: timestamp });
|
|
124
|
+
this.applyPartSnapshot(change, event.messageId, event.partIndex, event.part);
|
|
125
|
+
break;
|
|
126
|
+
case 'part.updated':
|
|
127
|
+
this.applyPartSnapshot(change, event.messageId, event.partIndex, event.part);
|
|
128
|
+
break;
|
|
129
|
+
case 'part.completed': {
|
|
130
|
+
const key = flexPartTimingKey(event.messageId, event.partId);
|
|
131
|
+
this.timings.set(key, { ...this.timings.get(key), endedAt: timestamp });
|
|
132
|
+
this.applyPartSnapshot(change, event.messageId, event.partIndex, event.part);
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
case 'part.delta':
|
|
136
|
+
this.applyPartDelta(change, event);
|
|
137
|
+
break;
|
|
138
|
+
case 'permission.requested':
|
|
139
|
+
this.permissionRows.set(event.request.permissionId, flexPermissionToHarness(event.request));
|
|
140
|
+
change.permissions = true;
|
|
141
|
+
break;
|
|
142
|
+
case 'permission.resolved': {
|
|
143
|
+
const row = this.permissionRows.get(event.request.permissionId);
|
|
144
|
+
if (!row)
|
|
145
|
+
break;
|
|
146
|
+
row.response = event.decision;
|
|
147
|
+
row.respondedAt = timestamp;
|
|
148
|
+
change.permissions = true;
|
|
149
|
+
break;
|
|
150
|
+
}
|
|
151
|
+
case 'run.finished':
|
|
152
|
+
this.upsertMessage(event.message);
|
|
153
|
+
change.messages = true;
|
|
154
|
+
if (event.message.usage) {
|
|
155
|
+
this.usage = sumUsage(this.usage, flexUsageToHarness(event.message.usage));
|
|
156
|
+
change.usage = true;
|
|
157
|
+
}
|
|
158
|
+
this.setStatus(change, event.status === 'failed'
|
|
159
|
+
? { type: 'error', ...(event.error ? { message: event.error.message } : {}) }
|
|
160
|
+
: { type: 'idle' });
|
|
161
|
+
break;
|
|
162
|
+
case 'prompt.started':
|
|
163
|
+
case 'prompt.running':
|
|
164
|
+
this.runningQueueId = event.queueId;
|
|
165
|
+
break;
|
|
166
|
+
case 'prompt.finished':
|
|
167
|
+
if (this.runningQueueId === event.queueId)
|
|
168
|
+
this.runningQueueId = undefined;
|
|
169
|
+
break;
|
|
170
|
+
case 'session.history.changed':
|
|
171
|
+
change.reload = true;
|
|
172
|
+
break;
|
|
173
|
+
default:
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
return change;
|
|
177
|
+
}
|
|
178
|
+
setStatus(change, status) {
|
|
179
|
+
if (status.type === this.status.type && status.message === this.status.message)
|
|
180
|
+
return;
|
|
181
|
+
this.status = status;
|
|
182
|
+
change.status = true;
|
|
183
|
+
}
|
|
184
|
+
upsertMessage(message) {
|
|
185
|
+
const index = this.flexMessages.findIndex((entry) => entry.messageId === message.messageId);
|
|
186
|
+
const copy = structuredClone(message);
|
|
187
|
+
if (index === -1)
|
|
188
|
+
this.flexMessages.push(copy);
|
|
189
|
+
else
|
|
190
|
+
this.flexMessages[index] = copy;
|
|
191
|
+
for (const part of copy.parts) {
|
|
192
|
+
if (part.type === 'text' || part.type === 'reasoning') {
|
|
193
|
+
this.partBytes.set(flexPartTimingKey(copy.messageId, part.partId), utf8.encode(part.text).length);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
applyPartSnapshot(change, messageId, partIndex, part) {
|
|
198
|
+
const message = this.flexMessages.find((entry) => entry.messageId === messageId);
|
|
199
|
+
if (!message || partIndex > message.parts.length) {
|
|
200
|
+
change.reload = true;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
const previous = message.parts[partIndex];
|
|
204
|
+
message.parts[partIndex] = structuredClone(part);
|
|
205
|
+
const key = flexPartTimingKey(messageId, part.partId);
|
|
206
|
+
if (part.type === 'text' || part.type === 'reasoning') {
|
|
207
|
+
this.partBytes.set(key, utf8.encode(part.text).length);
|
|
208
|
+
}
|
|
209
|
+
const rowId = flexPartRowId(messageId, part.partId);
|
|
210
|
+
if (previous?.partId !== part.partId || previous.type !== part.type) {
|
|
211
|
+
change.messages = true;
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (part.type === 'tool') {
|
|
215
|
+
change.deltas.push({
|
|
216
|
+
type: 'tool-update',
|
|
217
|
+
messageId: rowId,
|
|
218
|
+
tool: flexToolPartToHarness(part, this.timings.get(key)),
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
else if (part.type === 'text' && previous.type === 'text') {
|
|
222
|
+
if (previous.text !== part.text)
|
|
223
|
+
change.messages = true;
|
|
224
|
+
else if (message.status !== 'streaming' || partIndex !== message.parts.length - 1) {
|
|
225
|
+
change.deltas.push({ type: 'message-end', messageId: rowId });
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
else if (part.type === 'reasoning' && previous.type === 'reasoning') {
|
|
229
|
+
if (previous.text !== part.text)
|
|
230
|
+
change.messages = true;
|
|
231
|
+
else if (part.status !== 'running') {
|
|
232
|
+
change.deltas.push({
|
|
233
|
+
type: 'reasoning-end',
|
|
234
|
+
messageId: rowId,
|
|
235
|
+
partId: part.partId,
|
|
236
|
+
endedAt: this.timings.get(key)?.endedAt,
|
|
237
|
+
});
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
change.messages = true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
applyPartDelta(change, event) {
|
|
245
|
+
const message = this.flexMessages.find((entry) => entry.messageId === event.messageId);
|
|
246
|
+
const part = message?.parts[event.partIndex];
|
|
247
|
+
const key = flexPartTimingKey(event.messageId, event.partId);
|
|
248
|
+
if (!part
|
|
249
|
+
|| part.partId !== event.partId
|
|
250
|
+
|| part.type !== event.partType
|
|
251
|
+
|| this.partBytes.get(key) !== event.baseTextUtf8Bytes) {
|
|
252
|
+
change.reload = true;
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
const bytes = event.baseTextUtf8Bytes + appendedUtf8Bytes(part.text, event.delta);
|
|
256
|
+
if (bytes !== event.textUtf8Bytes) {
|
|
257
|
+
change.reload = true;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
part.text += event.delta;
|
|
261
|
+
this.partBytes.set(key, bytes);
|
|
262
|
+
const rowId = flexPartRowId(event.messageId, event.partId);
|
|
263
|
+
change.deltas.push(event.partType === 'text'
|
|
264
|
+
? { type: 'text', messageId: rowId, delta: event.delta }
|
|
265
|
+
: { type: 'reasoning', messageId: rowId, partId: event.partId, delta: event.delta });
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50cmFuc2NyaXB0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vdHNfY2hhdF9oYXJuZXNzL2NsYXNzZXMudHJhbnNjcmlwdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFTQSxPQUFPLEVBQ0wsd0JBQXdCLEVBQ3hCLGFBQWEsRUFDYixpQkFBaUIsRUFDakIsdUJBQXVCLEVBQ3ZCLDhCQUE4QixFQUM5Qix5QkFBeUIsRUFDekIsMEJBQTBCLEVBQzFCLHFCQUFxQixFQUNyQixrQkFBa0IsR0FFbkIsTUFBTSx3QkFBd0IsQ0FBQztBQXdEaEMsTUFBTSxJQUFJLEdBQUcsSUFBSSxXQUFXLEVBQUUsQ0FBQztBQUUvQixtRkFBbUY7QUFDbkYsU0FBUyxpQkFBaUIsQ0FBQyxJQUFZLEVBQUUsS0FBYTtJQUNwRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDbEQsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNwQyxNQUFNLGtCQUFrQixHQUFHLFFBQVEsSUFBSSxNQUFNLElBQUksUUFBUSxJQUFJLE1BQU07V0FDOUQsT0FBTyxJQUFJLE1BQU0sSUFBSSxPQUFPLElBQUksTUFBTSxDQUFDO0lBQzVDLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUNsRSxDQUFDO0FBRUQsU0FBUyxRQUFRLENBQ2YsS0FBNEIsRUFDNUIsS0FBNEI7SUFFNUIsTUFBTSxHQUFHLEdBQUcsQ0FBQyxHQUFnQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMs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
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type * as plugins from './plugins.js';
|
|
2
|
+
import type { FlexHarness } from '../dist_ts/classes.flexharness.js';
|
|
3
|
+
import type { IFlexPromptOptions, IFlexPromptQueueAdmission, TFlexPermissionDecision, TFlexPromptPart } from '../dist_ts/interfaces.js';
|
|
4
|
+
/** The session a chat view shows. */
|
|
5
|
+
export interface IFlexHarnessChatTarget {
|
|
6
|
+
scopeId: string;
|
|
7
|
+
sessionId: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* One call a chat view asks the harness to make, as plain data a host can carry from the browser
|
|
11
|
+
* to the server that owns the harness.
|
|
12
|
+
*/
|
|
13
|
+
export type TFlexHarnessChatIntent = (IFlexHarnessChatTarget & {
|
|
14
|
+
type: 'enqueuePrompt';
|
|
15
|
+
prompt: TFlexPromptPart[];
|
|
16
|
+
options: IFlexPromptOptions;
|
|
17
|
+
}) | (IFlexHarnessChatTarget & {
|
|
18
|
+
type: 'steerPrompt';
|
|
19
|
+
queueId: string;
|
|
20
|
+
steerId: string;
|
|
21
|
+
prompt: TFlexPromptPart[];
|
|
22
|
+
options: IFlexPromptOptions;
|
|
23
|
+
}) | (IFlexHarnessChatTarget & {
|
|
24
|
+
type: 'respondToPermission';
|
|
25
|
+
permissionId: string;
|
|
26
|
+
decision: TFlexPermissionDecision;
|
|
27
|
+
}) | (IFlexHarnessChatTarget & {
|
|
28
|
+
type: 'abort';
|
|
29
|
+
});
|
|
30
|
+
export interface IFlexHarnessSendIntentOptions {
|
|
31
|
+
/** The running queue entry, `FlexHarnessTranscript.activeQueueId`; a steer joins it. */
|
|
32
|
+
activeQueueId?: string;
|
|
33
|
+
/**
|
|
34
|
+
* The model hint the prompt carries. Defaults to the composer's `model`. A host that offers
|
|
35
|
+
* accounts or reasoning efforts encodes them in its own hint scheme here.
|
|
36
|
+
*/
|
|
37
|
+
modelHint?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Maps `harness-send`. A message sent while idle, or queued behind the running turn, becomes a
|
|
41
|
+
* queued prompt. A steer joins the running turn; with no running turn it is the next turn's
|
|
42
|
+
* input, so it is queued as well. A steer keeps the prompt options for that case only: it answers
|
|
43
|
+
* on the running turn's model. A steer id comes from `crypto.randomUUID()`, which browsers offer
|
|
44
|
+
* in secure contexts only (HTTPS or localhost).
|
|
45
|
+
*/
|
|
46
|
+
export declare function flexHarnessSendIntent(target: IFlexHarnessChatTarget, detail: plugins.IHarnessComposerSendDetail, options?: IFlexHarnessSendIntentOptions): TFlexHarnessChatIntent;
|
|
47
|
+
/**
|
|
48
|
+
* Maps `harness-permission-response`. The card reports a remembered approval as `remember`,
|
|
49
|
+
* which FlexHarness calls `always`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function flexHarnessPermissionIntent(target: IFlexHarnessChatTarget, detail: plugins.IHarnessPermissionResponseDetail): TFlexHarnessChatIntent;
|
|
52
|
+
/** Maps `harness-abort`. */
|
|
53
|
+
export declare function flexHarnessAbortIntent(target: IFlexHarnessChatTarget): TFlexHarnessChatIntent;
|
|
54
|
+
/** The harness calls `runFlexHarnessChatIntent` makes. */
|
|
55
|
+
export type TFlexHarnessChatHost = Pick<FlexHarness<unknown>, 'enqueuePrompt' | 'steerPrompt' | 'respondToPermission' | 'abort'>;
|
|
56
|
+
/**
|
|
57
|
+
* Makes the call an intent names, on the server that owns the harness, once the harness admitted
|
|
58
|
+
* it. A queued prompt returns its admission: its `completion` settles when the run ends, and the
|
|
59
|
+
* caller owns it, as with `enqueuePrompt()`. A steer whose turn ended before the harness took it
|
|
60
|
+
* is the next turn's input, so it is queued instead and returns that admission.
|
|
61
|
+
*/
|
|
62
|
+
export declare function runFlexHarnessChatIntent(harness: TFlexHarnessChatHost, intent: TFlexHarnessChatIntent): Promise<IFlexPromptQueueAdmission | undefined>;
|