@novoagents/react 0.3.0-alpha.4 → 0.3.0-alpha.40
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 +141 -100
- package/README.md +0 -23
- package/dist/useNovoRun.js +36 -20
- package/dist/useNovoRunSelector.js +58 -38
- package/package.json +11 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,102 +1,143 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
##
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
## 0.3.0-alpha.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
`
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
## 0.
|
|
42
|
-
|
|
43
|
-
- Companion release for `novoagents` 0.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
## 0.
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
3
|
+
## 0.3.0-alpha.40 - 2026-09-06
|
|
4
|
+
|
|
5
|
+
Companion release for `novoagents` 0.5.0-alpha.36. The React runtime is
|
|
6
|
+
unchanged; the exact peer carries the corrected public type and error exports.
|
|
7
|
+
Packed-consumer verification now runs from a staged copy and exercises the
|
|
8
|
+
workspace peer resolver independently.
|
|
9
|
+
|
|
10
|
+
## 0.3.0-alpha.39 - 2026-09-06
|
|
11
|
+
|
|
12
|
+
Companion release for `novoagents` 0.5.0-alpha.35. The React runtime is
|
|
13
|
+
unchanged; the exact peer carries the combined private-input and managed-web
|
|
14
|
+
usage contracts.
|
|
15
|
+
|
|
16
|
+
## 0.3.0-alpha.38 - 2026-09-06
|
|
17
|
+
|
|
18
|
+
Companion release for `novoagents` 0.5.0-alpha.34. The React runtime is
|
|
19
|
+
unchanged; the exact peer carries protected browser input and context revision
|
|
20
|
+
contracts.
|
|
21
|
+
|
|
22
|
+
## 0.3.0-alpha.37 - 2026-09-03
|
|
23
|
+
|
|
24
|
+
Companion release for `novoagents` 0.5.0-alpha.33. The React runtime is
|
|
25
|
+
unchanged; the exact peer carries the new agent configuration warnings type.
|
|
26
|
+
|
|
27
|
+
## 0.3.0-alpha.36 - 2026-09-01
|
|
28
|
+
|
|
29
|
+
Companion release for `novoagents` 0.5.0-alpha.32.
|
|
30
|
+
|
|
31
|
+
- Controller ownership now rides the external-store snapshot (run key and
|
|
32
|
+
controller travel with the subscribed state), so an abandoned concurrent
|
|
33
|
+
render can no longer strand ownership in a render-written ref. Selector
|
|
34
|
+
readers isolate speculative renders while preserving equal object identity
|
|
35
|
+
across inline selector changes: the committed selection lives in a
|
|
36
|
+
`useState`-held cell that is still read during render, by design, mirroring
|
|
37
|
+
React's own `useSyncExternalStoreWithSelector` shim. Behavior is unchanged
|
|
38
|
+
across React 18 and 19, and the package now passes the canonical hooks lint
|
|
39
|
+
rules.
|
|
40
|
+
|
|
41
|
+
## 0.3.0-alpha.35 - 2026-08-26
|
|
42
|
+
|
|
43
|
+
- Companion release for `novoagents` 0.5.0-alpha.31. GitHub connection and
|
|
44
|
+
agent repository grants now carry exact immutable repository identities
|
|
45
|
+
end to end; an explicit empty agent selection grants no repositories.
|
|
46
|
+
|
|
47
|
+
## 0.3.0-alpha.34 - 2026-08-26
|
|
48
|
+
|
|
49
|
+
- Companion release for `novoagents` 0.5.0-alpha.30. The React runtime is
|
|
50
|
+
unchanged; the exact peer carries the immutable repository id on grantable
|
|
51
|
+
GitHub repositories.
|
|
52
|
+
|
|
53
|
+
## 0.3.0-alpha.33 - 2026-08-26
|
|
54
|
+
|
|
55
|
+
- Companion release for `novoagents` 0.5.0-alpha.29. The React runtime is
|
|
56
|
+
unchanged; the exact peer carries the discriminated usage-lineage and
|
|
57
|
+
debit-group identity contract.
|
|
58
|
+
|
|
59
|
+
## 0.3.0-alpha.32 - 2026-08-25
|
|
60
|
+
|
|
61
|
+
- Companion release for `novoagents` 0.5.0-alpha.28. It carries the exact peer
|
|
62
|
+
for scheduled wake-ups, stream protocol 18, and customer wake-up
|
|
63
|
+
cancellation. The React runtime is unchanged.
|
|
64
|
+
|
|
65
|
+
## 0.3.0-alpha.31 - 2026-08-21
|
|
66
|
+
|
|
67
|
+
- Companion release for `novoagents` 0.5.0-alpha.27. The controller can follow
|
|
68
|
+
ordered thread segments with an injected cursor codec; React state exposes
|
|
69
|
+
the segment ledger while preserving the transcript across engine-owned runs.
|
|
70
|
+
|
|
71
|
+
## 0.3.0-alpha.27 - 2026-08-20
|
|
72
|
+
|
|
73
|
+
- Companion release for `novoagents` 0.5.0-alpha.25. The React runtime is
|
|
74
|
+
unchanged; the exact peer carries autonomous run starts and all-attempt Stop
|
|
75
|
+
semantics for background subagents.
|
|
76
|
+
|
|
77
|
+
## 0.3.0-alpha.26 - 2026-08-20
|
|
78
|
+
|
|
79
|
+
- Companion release for `novoagents` 0.5.0-alpha.24. It carries the exact peer
|
|
80
|
+
for wire protocol 16, the shared GitHub installation contract, and the
|
|
81
|
+
`ask_question` lifecycle whose first public terminal is the user's real
|
|
82
|
+
resolution.
|
|
83
|
+
|
|
84
|
+
## 0.3.0-alpha.25 - 2026-08-20
|
|
85
|
+
|
|
86
|
+
- Companion release for `novoagents` 0.5.0-alpha.23. It carries the exact peer
|
|
87
|
+
required for stream schema 14, including background worker task metadata and
|
|
88
|
+
`data-novo-worker-report` message parts.
|
|
89
|
+
|
|
90
|
+
## 0.3.0-alpha.24 - 2026-08-18
|
|
91
|
+
|
|
92
|
+
- Companion release for `novoagents` 0.5.0-alpha.22. The hook runtime is
|
|
93
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
94
|
+
run controller it binds. Consumers rendering `run.messages` now see one
|
|
95
|
+
`data-novo-heartbeat` part per tool wait (see the core changelog).
|
|
96
|
+
|
|
97
|
+
## 0.3.0-alpha.23 - 2026-08-17
|
|
98
|
+
|
|
99
|
+
- Companion release for `novoagents` 0.5.0-alpha.21. The hook runtime is
|
|
100
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
101
|
+
run controller it binds.
|
|
102
|
+
|
|
103
|
+
## 0.3.0-alpha.22 - 2026-08-17
|
|
104
|
+
|
|
105
|
+
- Companion release for `novoagents` 0.5.0-alpha.20. The hook runtime is
|
|
106
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
107
|
+
run controller it binds.
|
|
108
|
+
|
|
109
|
+
## 0.3.0-alpha.21 - 2026-08-17
|
|
110
|
+
|
|
111
|
+
- Companion release for `novoagents` 0.5.0-alpha.19. The hook runtime is
|
|
112
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
113
|
+
run controller it binds.
|
|
114
|
+
|
|
115
|
+
## 0.3.0-alpha.20 - 2026-08-16
|
|
116
|
+
|
|
117
|
+
- Companion release for `novoagents` 0.5.0-alpha.18. The hook runtime is
|
|
118
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
119
|
+
run controller it binds.
|
|
120
|
+
- `0.3.0-alpha.19` was published through npm instead of pnpm and therefore
|
|
121
|
+
preserved the workspace protocol in its peer metadata. It was never tagged
|
|
122
|
+
`latest`; use this build instead.
|
|
123
|
+
|
|
124
|
+
## 0.3.0-alpha.18 - 2026-08-12
|
|
125
|
+
|
|
126
|
+
- Companion release for `novoagents` 0.5.0-alpha.17. The hook runtime is
|
|
127
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
128
|
+
run controller it binds.
|
|
129
|
+
|
|
130
|
+
## 0.3.0-alpha.17 - 2026-08-12
|
|
131
|
+
|
|
132
|
+
- Companion release for `novoagents` 0.5.0-alpha.16. The hook runtime is
|
|
133
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
134
|
+
run controller it binds.
|
|
135
|
+
|
|
136
|
+
## 0.3.0-alpha.16 - 2026-08-12
|
|
137
|
+
|
|
138
|
+
- Companion release for `novoagents` 0.5.0-alpha.15. The hook runtime is
|
|
139
|
+
unchanged; the package carries an exact peer on the SDK version whose browser
|
|
140
|
+
run controller it binds.
|
|
141
|
+
|
|
142
|
+
Earlier prerelease builds are unsupported. Their immutable package artifacts
|
|
143
|
+
and Git history retain their release records.
|
package/README.md
CHANGED
|
@@ -48,26 +48,3 @@ If your host persists interaction requests independently of the stream,
|
|
|
48
48
|
configure `interactionDiscovery: { list, intervalMs? }` on the controller.
|
|
49
49
|
Discovery is generation-fenced, runs while the SSE connection is idle, and
|
|
50
50
|
reconciles DB-only requests into the same canonical pending queue.
|
|
51
|
-
|
|
52
|
-
## Migrating from 0.1.0-alpha.0
|
|
53
|
-
|
|
54
|
-
- `createNovoRunStore` → `createNovoRunController` from `novoagents/browser`.
|
|
55
|
-
- `BrowserRunTransport` → `NovoRunEventSource`; use
|
|
56
|
-
`createNovoHttpRunSource` for fetch/SSE routes.
|
|
57
|
-
- `useNovoRun({ transport })` →
|
|
58
|
-
`useNovoRun({ createController, runKey })`.
|
|
59
|
-
- `useNovoInteractions({ endpoint, run })` → configure the controller's
|
|
60
|
-
interaction transport, then call `useNovoInteractions(run.controller)`.
|
|
61
|
-
- `resolveNovoInteractions` → `createHttpInteractionResolveTransport`.
|
|
62
|
-
|
|
63
|
-
There are no compatibility aliases for the alpha API.
|
|
64
|
-
|
|
65
|
-
## Publishing
|
|
66
|
-
|
|
67
|
-
After publishing `novoagents`, publish with
|
|
68
|
-
`pnpm publish --access public --tag alpha`: pnpm rewrites the `workspace:*`
|
|
69
|
-
peer dependency on `novoagents` to the exact packed version. Publish the two
|
|
70
|
-
alpha packages in lockstep so both `alpha` tags always form one compatible
|
|
71
|
-
browser-controller installation. Do not publish the workspace source with
|
|
72
|
-
`npm publish`; npm does not perform pnpm's workspace-protocol rewrite. Verify
|
|
73
|
-
the registry peer metadata before moving `latest`.
|
package/dist/useNovoRun.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useEffect, useMemo, useRef, useSyncExternalStore } from 'react';
|
|
2
|
+
import { useEffect, useMemo, useRef, useState, useSyncExternalStore, } from 'react';
|
|
3
3
|
export const NOVO_IDLE_RUN_STATE = Object.freeze({
|
|
4
4
|
messages: Object.freeze([]),
|
|
5
5
|
status: 'queued',
|
|
6
6
|
progress: null,
|
|
7
7
|
pendingInteractions: Object.freeze([]),
|
|
8
8
|
tasks: Object.freeze([]),
|
|
9
|
+
segments: Object.freeze([]),
|
|
9
10
|
steps: Object.freeze([]),
|
|
10
11
|
browserSessions: Object.freeze([]),
|
|
11
12
|
warnings: Object.freeze([]),
|
|
@@ -21,7 +22,17 @@ function createControllerSlot() {
|
|
|
21
22
|
const listeners = new Set();
|
|
22
23
|
let controller;
|
|
23
24
|
let unsubscribe;
|
|
25
|
+
let snapshot = {
|
|
26
|
+
controller: undefined,
|
|
27
|
+
runKey: UNOWNED_RUN_KEY,
|
|
28
|
+
state: NOVO_IDLE_RUN_STATE,
|
|
29
|
+
};
|
|
24
30
|
const publish = () => {
|
|
31
|
+
snapshot = {
|
|
32
|
+
...snapshot,
|
|
33
|
+
state: controller?.getSnapshot() ??
|
|
34
|
+
NOVO_IDLE_RUN_STATE,
|
|
35
|
+
};
|
|
25
36
|
for (const listener of listeners)
|
|
26
37
|
listener();
|
|
27
38
|
};
|
|
@@ -30,15 +41,20 @@ function createControllerSlot() {
|
|
|
30
41
|
listeners.add(listener);
|
|
31
42
|
return () => listeners.delete(listener);
|
|
32
43
|
},
|
|
33
|
-
getSnapshot: () =>
|
|
34
|
-
NOVO_IDLE_RUN_STATE,
|
|
44
|
+
getSnapshot: () => snapshot,
|
|
35
45
|
getController: () => controller,
|
|
36
|
-
setController(next) {
|
|
37
|
-
if (controller === next)
|
|
46
|
+
setController(next, runKey = UNOWNED_RUN_KEY) {
|
|
47
|
+
if (controller === next && snapshot.runKey === runKey)
|
|
38
48
|
return;
|
|
39
49
|
unsubscribe?.();
|
|
40
50
|
controller = next;
|
|
41
51
|
unsubscribe = next?.subscribe(publish);
|
|
52
|
+
snapshot = {
|
|
53
|
+
controller: next,
|
|
54
|
+
runKey,
|
|
55
|
+
state: next?.getSnapshot() ??
|
|
56
|
+
NOVO_IDLE_RUN_STATE,
|
|
57
|
+
};
|
|
42
58
|
publish();
|
|
43
59
|
},
|
|
44
60
|
};
|
|
@@ -50,11 +66,10 @@ function createControllerSlot() {
|
|
|
50
66
|
*/
|
|
51
67
|
export function useNovoRun(options) {
|
|
52
68
|
const factoryRef = useRef(options.createController);
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
const slot =
|
|
57
|
-
const ownedRunKeyRef = useRef(UNOWNED_RUN_KEY);
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
factoryRef.current = options.createController;
|
|
71
|
+
}, [options.createController]);
|
|
72
|
+
const [slot] = useState(() => createControllerSlot());
|
|
58
73
|
// Normalize before any dependency array: `enabled: undefined <-> true` and
|
|
59
74
|
// `runKey: undefined <-> null` toggles are identity changes and must not
|
|
60
75
|
// dispose and recreate a live controller.
|
|
@@ -66,14 +81,10 @@ export function useNovoRun(options) {
|
|
|
66
81
|
return;
|
|
67
82
|
}
|
|
68
83
|
const controller = factoryRef.current();
|
|
69
|
-
|
|
70
|
-
slot.setController(controller);
|
|
84
|
+
slot.setController(controller, runKey);
|
|
71
85
|
return () => {
|
|
72
86
|
controller.stop();
|
|
73
87
|
controller.dispose();
|
|
74
|
-
if (ownedRunKeyRef.current === runKey) {
|
|
75
|
-
ownedRunKeyRef.current = UNOWNED_RUN_KEY;
|
|
76
|
-
}
|
|
77
88
|
if (slot.getController() === controller)
|
|
78
89
|
slot.setController(undefined);
|
|
79
90
|
};
|
|
@@ -81,16 +92,16 @@ export function useNovoRun(options) {
|
|
|
81
92
|
useEffect(() => {
|
|
82
93
|
if (enabled &&
|
|
83
94
|
options.autoStart !== false &&
|
|
84
|
-
|
|
95
|
+
slot.getSnapshot().runKey === runKey) {
|
|
85
96
|
void slot.getController()?.start();
|
|
86
97
|
}
|
|
87
98
|
}, [options.autoStart, enabled, runKey, slot]);
|
|
88
|
-
const
|
|
89
|
-
const ownsRenderedKey = enabled &&
|
|
99
|
+
const observed = useSyncExternalStore(slot.subscribe, slot.getSnapshot, () => IDLE_SLOT_SNAPSHOT);
|
|
100
|
+
const ownsRenderedKey = enabled && observed.runKey === runKey;
|
|
90
101
|
const state = ownsRenderedKey
|
|
91
|
-
?
|
|
102
|
+
? observed.state
|
|
92
103
|
: NOVO_IDLE_RUN_STATE;
|
|
93
|
-
const controller = ownsRenderedKey ?
|
|
104
|
+
const controller = ownsRenderedKey ? observed.controller : undefined;
|
|
94
105
|
return useMemo(() => ({
|
|
95
106
|
...state,
|
|
96
107
|
controller,
|
|
@@ -104,3 +115,8 @@ export function useNovoRun(options) {
|
|
|
104
115
|
}), [controller, state]);
|
|
105
116
|
}
|
|
106
117
|
const UNOWNED_RUN_KEY = Symbol('unowned Novo run key');
|
|
118
|
+
const IDLE_SLOT_SNAPSHOT = Object.freeze({
|
|
119
|
+
controller: undefined,
|
|
120
|
+
runKey: UNOWNED_RUN_KEY,
|
|
121
|
+
state: NOVO_IDLE_RUN_STATE,
|
|
122
|
+
});
|
|
@@ -1,47 +1,67 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { useCallback, useEffect, useMemo,
|
|
2
|
+
import { useCallback, useEffect, useMemo, useState, useSyncExternalStore, } from 'react';
|
|
3
3
|
import { NOVO_IDLE_RUN_STATE } from './useNovoRun.js';
|
|
4
4
|
/** Concurrent-safe selector binding with selector/equality identity support. */
|
|
5
5
|
export function useNovoRunSelector(controller, selector, isEqual = Object.is) {
|
|
6
|
-
const committedSelection =
|
|
7
|
-
|
|
8
|
-
});
|
|
9
|
-
const idleState = NOVO_IDLE_RUN_STATE;
|
|
10
|
-
const [getSnapshot, getServerSnapshot] = useMemo(() => {
|
|
11
|
-
let hasMemo = false;
|
|
12
|
-
let memoizedState;
|
|
13
|
-
let memoizedSelection;
|
|
14
|
-
const select = (state) => {
|
|
15
|
-
if (!hasMemo) {
|
|
16
|
-
hasMemo = true;
|
|
17
|
-
memoizedState = state;
|
|
18
|
-
const nextSelection = selector(state);
|
|
19
|
-
const committed = committedSelection.current;
|
|
20
|
-
memoizedSelection =
|
|
21
|
-
committed.hasValue && isEqual(committed.value, nextSelection)
|
|
22
|
-
? committed.value
|
|
23
|
-
: nextSelection;
|
|
24
|
-
return memoizedSelection;
|
|
25
|
-
}
|
|
26
|
-
if (Object.is(memoizedState, state))
|
|
27
|
-
return memoizedSelection;
|
|
28
|
-
const nextSelection = selector(state);
|
|
29
|
-
memoizedState = state;
|
|
30
|
-
if (isEqual(memoizedSelection, nextSelection))
|
|
31
|
-
return memoizedSelection;
|
|
32
|
-
memoizedSelection = nextSelection;
|
|
33
|
-
return memoizedSelection;
|
|
34
|
-
};
|
|
35
|
-
const serverSelection = select(idleState);
|
|
36
|
-
return [
|
|
37
|
-
() => select(controller?.getSnapshot() ?? idleState),
|
|
38
|
-
() => serverSelection,
|
|
39
|
-
];
|
|
40
|
-
}, [controller, isEqual, selector]);
|
|
6
|
+
const [committedSelection] = useState(() => createCommittedSelection());
|
|
7
|
+
const [getSnapshot, getServerSnapshot] = useMemo(() => createSelectionReader(controller, selector, isEqual, NOVO_IDLE_RUN_STATE, committedSelection), [committedSelection, controller, isEqual, selector]);
|
|
41
8
|
const subscribe = useCallback((listener) => controller?.subscribe(listener) ?? (() => { }), [controller]);
|
|
42
9
|
const selection = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
43
10
|
useEffect(() => {
|
|
44
|
-
committedSelection.
|
|
45
|
-
}, [selection]);
|
|
11
|
+
committedSelection.write(selection);
|
|
12
|
+
}, [committedSelection, selection]);
|
|
46
13
|
return selection;
|
|
47
14
|
}
|
|
15
|
+
// Deliberately a mutable cell read during render (via getSnapshot) and
|
|
16
|
+
// written from the commit effect, mirroring React's own
|
|
17
|
+
// useSyncExternalStoreWithSelector shim. The hooks lint layer cannot see a
|
|
18
|
+
// closure-held cell; do not "fix" this back into a ref, which it would flag.
|
|
19
|
+
function createCommittedSelection() {
|
|
20
|
+
let committed = {
|
|
21
|
+
hasValue: false,
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
read: () => committed,
|
|
25
|
+
write: (value) => {
|
|
26
|
+
committed = { hasValue: true, value };
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function createSelectionReader(controller, selector, isEqual, idleState, committedSelection) {
|
|
31
|
+
let hasValue = false;
|
|
32
|
+
let value;
|
|
33
|
+
let memoizedState;
|
|
34
|
+
let hasServerValue = false;
|
|
35
|
+
let serverValue;
|
|
36
|
+
const select = (state) => {
|
|
37
|
+
if (Object.is(memoizedState, state) && hasValue)
|
|
38
|
+
return value;
|
|
39
|
+
const next = selector(state);
|
|
40
|
+
memoizedState = state;
|
|
41
|
+
if (!hasValue) {
|
|
42
|
+
hasValue = true;
|
|
43
|
+
const committed = committedSelection.read();
|
|
44
|
+
value =
|
|
45
|
+
committed.hasValue && isEqual(committed.value, next)
|
|
46
|
+
? committed.value
|
|
47
|
+
: next;
|
|
48
|
+
}
|
|
49
|
+
else if (!isEqual(value, next)) {
|
|
50
|
+
value = next;
|
|
51
|
+
}
|
|
52
|
+
return value;
|
|
53
|
+
};
|
|
54
|
+
const selectServer = () => {
|
|
55
|
+
if (hasServerValue)
|
|
56
|
+
return serverValue;
|
|
57
|
+
const next = selector(idleState);
|
|
58
|
+
const committed = committedSelection.read();
|
|
59
|
+
serverValue =
|
|
60
|
+
committed.hasValue && isEqual(committed.value, next)
|
|
61
|
+
? committed.value
|
|
62
|
+
: next;
|
|
63
|
+
hasServerValue = true;
|
|
64
|
+
return serverValue;
|
|
65
|
+
};
|
|
66
|
+
return [() => select(controller?.getSnapshot() ?? idleState), selectServer];
|
|
67
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@novoagents/react",
|
|
3
|
-
"version": "0.3.0-alpha.
|
|
3
|
+
"version": "0.3.0-alpha.40",
|
|
4
4
|
"description": "Browser-safe React hooks for Novo Agents streams and interactions.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|
|
@@ -23,19 +23,19 @@
|
|
|
23
23
|
"access": "public"
|
|
24
24
|
},
|
|
25
25
|
"peerDependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
26
|
+
"novoagents": "0.5.0-alpha.36",
|
|
27
|
+
"react": "^18.0.0 || ^19.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@types/react": "19.2.
|
|
31
|
-
"@types/react-dom": "19.2.
|
|
32
|
-
"happy-dom": "20.
|
|
33
|
-
"
|
|
34
|
-
"react
|
|
30
|
+
"@types/react": "19.2.18",
|
|
31
|
+
"@types/react-dom": "19.2.7",
|
|
32
|
+
"happy-dom": "20.14.0",
|
|
33
|
+
"novoagents": "0.5.0-alpha.36",
|
|
34
|
+
"react": "19.2.8",
|
|
35
|
+
"react-dom": "19.2.8",
|
|
35
36
|
"typescript": "6.0.3",
|
|
36
|
-
"vite": "8.
|
|
37
|
-
"vitest": "5.0.0
|
|
38
|
-
"novoagents": "0.5.0-alpha.4"
|
|
37
|
+
"vite": "8.2.2",
|
|
38
|
+
"vitest": "5.0.0"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -p tsconfig.json && node scripts/check-dist.mjs",
|