@modelprofile.com/flexharness 11.3.0 → 12.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist_ts/00_commitinfo_data.js +1 -1
  2. package/dist_ts/classes.flexharness.core.d.ts +4 -0
  3. package/dist_ts/classes.flexharness.core.js +69 -25
  4. package/dist_ts/classes.flexharness.imports.js +4 -3
  5. package/dist_ts/classes.flexharness.reversions.d.ts +7 -1
  6. package/dist_ts/classes.flexharness.reversions.js +43 -29
  7. package/dist_ts/classes.flexharness.sessions.js +2 -6
  8. package/dist_ts/classes.stores.js +20 -18
  9. package/dist_ts/index.d.ts +1 -0
  10. package/dist_ts/index.js +2 -1
  11. package/dist_ts/interfaces.d.ts +24 -2
  12. package/dist_ts/interfaces.flexharness.d.ts +8 -1
  13. package/dist_ts/interfaces.js +1 -1
  14. package/dist_ts/plugins.d.ts +3 -3
  15. package/dist_ts/plugins.js +3 -3
  16. package/dist_ts/utils.projectionchange.d.ts +34 -0
  17. package/dist_ts/utils.projectionchange.js +135 -0
  18. package/dist_ts/utils.storecodecs.d.ts +10 -3
  19. package/dist_ts/utils.storecodecs.js +29 -4
  20. package/dist_ts/utils.storerules.d.ts +1 -1
  21. package/dist_ts/utils.storerules.js +1 -1
  22. package/dist_ts_migration/v3_legacyflexharness.js +6 -5
  23. package/dist_ts_stores_nosqldb/classes.nosqldbstores.d.ts +5 -4
  24. package/dist_ts_stores_nosqldb/classes.nosqldbstores.js +56 -54
  25. package/dist_ts_stores_nosqldb/classes.recordstore.d.ts +176 -19
  26. package/dist_ts_stores_nosqldb/classes.recordstore.js +392 -67
  27. package/dist_ts_stores_nosqldb/index.d.ts +1 -1
  28. package/dist_ts_stores_nosqldb/index.js +2 -2
  29. package/dist_ts_stores_nosqldb/plugins.d.ts +1 -1
  30. package/dist_ts_stores_nosqldb/plugins.js +1 -1
  31. package/dist_ts_stores_testing/contract.d.ts +33 -0
  32. package/dist_ts_stores_testing/contract.js +566 -0
  33. package/dist_ts_stores_testing/fixtures.d.ts +20 -0
  34. package/dist_ts_stores_testing/fixtures.js +112 -0
  35. package/dist_ts_stores_testing/index.d.ts +2 -0
  36. package/dist_ts_stores_testing/index.js +3 -0
  37. package/dist_ts_stores_testing/plugins.d.ts +5 -0
  38. package/dist_ts_stores_testing/plugins.js +7 -0
  39. package/package.json +9 -3
  40. package/readme.md +6 -3
  41. package/ts/00_commitinfo_data.ts +1 -1
  42. package/ts/classes.flexharness.core.ts +74 -24
  43. package/ts/classes.flexharness.imports.ts +3 -2
  44. package/ts/classes.flexharness.reversions.ts +53 -28
  45. package/ts/classes.flexharness.sessions.ts +2 -5
  46. package/ts/classes.stores.ts +40 -37
  47. package/ts/index.ts +5 -0
  48. package/ts/interfaces.flexharness.ts +8 -1
  49. package/ts/interfaces.ts +27 -2
  50. package/ts/plugins.ts +12 -7
  51. package/ts/readme.md +6 -3
  52. package/ts/utils.projectionchange.ts +190 -0
  53. package/ts/utils.storecodecs.ts +42 -7
  54. package/ts/utils.storerules.ts +2 -2
  55. package/ts_migration/v3_legacyflexharness.ts +11 -6
  56. package/ts_stores_nosqldb/classes.nosqldbstores.ts +79 -71
  57. package/ts_stores_nosqldb/classes.recordstore.ts +491 -66
  58. package/ts_stores_nosqldb/index.ts +1 -0
  59. package/ts_stores_nosqldb/plugins.ts +4 -3
  60. package/ts_stores_nosqldb/readme.md +6 -2
  61. package/ts_stores_testing/contract.ts +776 -0
  62. package/ts_stores_testing/fixtures.ts +127 -0
  63. package/ts_stores_testing/index.ts +17 -0
  64. package/ts_stores_testing/plugins.ts +20 -0
  65. package/ts_stores_testing/readme.md +62 -0
@@ -0,0 +1,127 @@
1
+ import * as plugins from './plugins.js';
2
+ import type {
3
+ IFlexMessage,
4
+ IFlexPermissionSnapshot,
5
+ IFlexProjectionSnapshotCurrent,
6
+ IFlexReversionSegment,
7
+ IFlexScopeSnapshot,
8
+ } from '../ts/interfaces.js';
9
+
10
+ /** A scope snapshot with one idle session. */
11
+ export function scopeSnapshot(revision: number, sessionId = 'session-1'): IFlexScopeSnapshot {
12
+ return {
13
+ schemaVersion: 1,
14
+ revision,
15
+ sessions: [
16
+ {
17
+ scopeId: 'scope-1',
18
+ sessionId,
19
+ createdAt: '2026-08-05T00:00:00.000Z',
20
+ updatedAt: '2026-08-05T00:00:00.000Z',
21
+ status: 'idle',
22
+ activity: { status: 'idle' },
23
+ },
24
+ ],
25
+ tombstones: [],
26
+ };
27
+ }
28
+
29
+ /** An empty projection. */
30
+ export function projectionSnapshot(revision: number): IFlexProjectionSnapshotCurrent {
31
+ return {
32
+ schemaVersion: 3,
33
+ revision,
34
+ messages: [],
35
+ stagedTerminals: [],
36
+ reversionSegments: [],
37
+ revertCursor: 0,
38
+ excludedRunIds: [],
39
+ pendingReversionReleases: [],
40
+ };
41
+ }
42
+
43
+ /** The user and assistant message of one completed run of `session-1`. */
44
+ export function runMessages(runId: string): IFlexMessage[] {
45
+ return [{
46
+ messageId: `user-${runId}`,
47
+ sessionId: 'session-1',
48
+ runId,
49
+ role: 'user',
50
+ status: 'completed',
51
+ createdAt: '2026-08-05T00:00:00.000Z',
52
+ completedAt: '2026-08-05T00:00:01.000Z',
53
+ parts: [{ partId: `user-part-${runId}`, type: 'text', text: runId }],
54
+ }, {
55
+ messageId: `assistant-${runId}`,
56
+ sessionId: 'session-1',
57
+ runId,
58
+ role: 'assistant',
59
+ status: 'completed',
60
+ createdAt: '2026-08-05T00:00:00.000Z',
61
+ completedAt: '2026-08-05T00:00:01.000Z',
62
+ parts: [{ partId: `assistant-part-${runId}`, type: 'text', text: 'answer' }],
63
+ }];
64
+ }
65
+
66
+ /** The reversion segment of one completed run, without a workspace capture. */
67
+ export function runSegment(runId: string): IFlexReversionSegment {
68
+ return {
69
+ runId,
70
+ userMessageId: `user-${runId}`,
71
+ status: 'completed',
72
+ contextAvailable: true,
73
+ eventIds: [`event-${runId}`],
74
+ workspaceCaptured: false,
75
+ protocolVersion: 1,
76
+ provenance: 'transcript',
77
+ };
78
+ }
79
+
80
+ /** A projection of completed runs of `session-1`, each with its messages and reversion segment. */
81
+ export function projectionWithRuns(revision: number, runIds: string[]): IFlexProjectionSnapshotCurrent {
82
+ return {
83
+ ...projectionSnapshot(revision),
84
+ messages: runIds.flatMap(runMessages),
85
+ reversionSegments: runIds.map(runSegment),
86
+ revertCursor: runIds.length,
87
+ };
88
+ }
89
+
90
+ /** A permission snapshot that remembers one approval. */
91
+ export function permissionSnapshot(revision: number): IFlexPermissionSnapshot {
92
+ return {
93
+ schemaVersion: 1,
94
+ revision,
95
+ rememberedPermissionKeys: ['shell:approved'],
96
+ };
97
+ }
98
+
99
+ /** A system message event. */
100
+ export function agentEvent(id = 'event-1', content = 'System prompt'): plugins.ISystemMessageEvent {
101
+ return plugins.createAgentEvent<plugins.ISystemMessageEvent>({
102
+ id,
103
+ timestamp: 1,
104
+ type: 'system-message',
105
+ content,
106
+ });
107
+ }
108
+
109
+ /** The Agent event change that appends `events`. */
110
+ export function appendEvents(...events: plugins.TAgentEvent[]): plugins.IAgentEventChange {
111
+ return { remove: [], replace: [], append: events };
112
+ }
113
+
114
+ /** A finished shell job. */
115
+ export function finishedJob(executionId = 'job-1'): plugins.IToolJobState {
116
+ return {
117
+ executionId,
118
+ type: 'shell',
119
+ state: 'finished',
120
+ exitCode: 0,
121
+ stdout: 'ok',
122
+ stderr: '',
123
+ startedAt: 1,
124
+ updatedAt: 2,
125
+ finishedAt: 2,
126
+ };
127
+ }
@@ -0,0 +1,17 @@
1
+ export {
2
+ createFlexStoreContractTests,
3
+ type IFlexStoreContractBackend,
4
+ type IFlexStoreContractFixture,
5
+ type IFlexStoreContractTest,
6
+ } from './contract.js';
7
+ export {
8
+ agentEvent,
9
+ appendEvents,
10
+ finishedJob,
11
+ permissionSnapshot,
12
+ projectionSnapshot,
13
+ projectionWithRuns,
14
+ runMessages,
15
+ runSegment,
16
+ scopeSnapshot,
17
+ } from './fixtures.js';
@@ -0,0 +1,20 @@
1
+ // node native scope
2
+ import { strict as assert } from 'node:assert';
3
+
4
+ export { assert };
5
+
6
+ // @modelprofile.com scope
7
+ import {
8
+ AgentEventStoreConflictError,
9
+ ToolJobStoreConflictError,
10
+ createAgentEvent,
11
+ } from '@modelprofile.com/flexharness-agent';
12
+
13
+ export { AgentEventStoreConflictError, ToolJobStoreConflictError, createAgentEvent };
14
+ export type {
15
+ IAgentEventArchive,
16
+ IAgentEventChange,
17
+ ISystemMessageEvent,
18
+ IToolJobState,
19
+ TAgentEvent,
20
+ } from '@modelprofile.com/flexharness-agent';
@@ -0,0 +1,62 @@
1
+ The store contract of FlexHarness as test cases for any test runner: the behaviour every built-in `IFlexHarnessStores` bundle passes, to run against a custom one.
2
+
3
+ ```sh
4
+ pnpm add @modelprofile.com/flexharness
5
+ ```
6
+
7
+ ```typescript
8
+ import { test } from 'node:test';
9
+ import { createFlexStoreContractTests } from '@modelprofile.com/flexharness/stores/testing';
10
+
11
+ for (const contractTest of createFlexStoreContractTests({
12
+ name: 'my stores',
13
+ sharedBackingStore: true,
14
+ releasesSessions: false,
15
+ storesResults: false,
16
+ async open() {
17
+ const database = await createDisposableDatabase();
18
+ return {
19
+ stores: new MyFlexHarnessStores(database),
20
+ openPeer: async () => new MyFlexHarnessStores(database.connectAgain()),
21
+ close: () => database.drop(),
22
+ };
23
+ },
24
+ })) {
25
+ test(contractTest.title, () => contractTest.run());
26
+ }
27
+ ```
28
+
29
+ `createFlexStoreContractTests(backend)` returns one `{ title, run() }` per case; `run()` resolves when the case passes and throws a `node:assert` error, or the store's own error, when it fails. Each case calls `backend.open()` for a fixture over an empty backing store and closes it afterwards, also when it fails, so the backend needs no cleanup between cases and the cases may run in any order. The backend declares what its bundle offers, and the cases that need more are left out:
30
+
31
+ - `sharedBackingStore`: several bundles can open one backing store, as separate processes would. The fixture's `openPeer()` opens another, and a case checks that the bundles share compare-and-swap revisions.
32
+ - `releasesSessions`: the Agent event and tool job providers implement `releaseSession`, which must evict their session wrappers without deleting stored data.
33
+ - `storesResults`: the bundle provides the optional `results` store.
34
+
35
+ The cases cover compare-and-swap revisions and the conflict errors that report them, cloning at the store boundary, session and storage key isolation, the snapshot validation every domain applies, and the change-based saves of projections and Agent events: a projection change keeps the stored entries its list changes name and appends the rest, an Agent event change removes, replaces and appends events, and a change that does not fit the stored value never loads, whether the store rejects it when it saves the change or when it next loads the value. The cases await every store call, as FlexHarness does, so a store method may reject or throw.
36
+
37
+ A store that keeps snapshots implements the change-based saves with the helpers of the root and Agent packages: `assertFlexProjectionChange()` and `applyFlexProjectionChange()` from `@modelprofile.com/flexharness`, `assertAgentEventChange()` and `applyAgentEventChange()` from `@modelprofile.com/flexharness-agent`, followed by the snapshot validators the root readme lists. The fixture builders the cases use, such as `projectionWithRuns()` and `appendEvents()`, are exported too, for a backend's own tests.
38
+
39
+ ## Issue Reporting and Security
40
+
41
+ For reporting bugs, issues, or security vulnerabilities, please visit [community.foss.global/](https://community.foss.global/). This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a [code.foss.global/](https://code.foss.global/) account to submit Pull Requests directly.
42
+
43
+ ## License and Legal Information
44
+
45
+ This repository contains open-source code licensed under the MIT License. A copy of the license can be found in the repository license file.
46
+
47
+ **Please note:** The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
48
+
49
+ ### Trademarks
50
+
51
+ This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
52
+
53
+ Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
54
+
55
+ ### Company Information
56
+
57
+ Task Venture Capital GmbH<br>
58
+ Registered at District Court Bremen HRB 35230 HB, Germany
59
+
60
+ For any legal inquiries or further information, please contact us via email at hello@task.vc.
61
+
62
+ By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.