@qorejs/qore 1.0.0 → 1.0.2

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/docs/react.md ADDED
@@ -0,0 +1,102 @@
1
+ # React Adapter
2
+
3
+ Qore's core runtime is framework-neutral. The React adapter lets React apps consume Qore streams without treating streaming as a special rendering case.
4
+
5
+ ```bash
6
+ npm i @qorejs/qore @qorejs/react
7
+ ```
8
+
9
+ ## Why It Exists
10
+
11
+ React is still the UI shell for many production AI products. Qore should not force those teams to switch renderers before they can use `stream = signal`.
12
+
13
+ The adapter keeps Qore in the streaming runtime layer:
14
+
15
+ ```text
16
+ Provider / AsyncIterable
17
+ -> QoreStream
18
+ -> React external store
19
+ -> Component view
20
+ ```
21
+
22
+ A `QoreStream` remains the source of truth. React subscribes to it through `useSyncExternalStore`, which is the React-supported bridge for external reactive stores.
23
+
24
+ ## useQoreStream
25
+
26
+ Use `useQoreStream` when a component owns the stream lifecycle.
27
+
28
+ ```tsx
29
+ import { stream } from '@qorejs/qore';
30
+ import { useQoreStream } from '@qorejs/react';
31
+
32
+ export function Answer({ prompt }: { prompt: string }) {
33
+ const answer = useQoreStream(
34
+ () => stream(fetch(`/api/chat?prompt=${encodeURIComponent(prompt)}`).then((response) => response.body)),
35
+ [prompt],
36
+ { initialValue: '' }
37
+ );
38
+
39
+ return (
40
+ <article>
41
+ <p>{answer.value}</p>
42
+ <small>{answer.status}</small>
43
+ <button onClick={() => answer.abort()}>Stop</button>
44
+ </article>
45
+ );
46
+ }
47
+ ```
48
+
49
+ When dependencies change, the hook aborts the previous stream and starts a new one. When the component unmounts, the active stream is aborted. Pass `{ enabled: false }` to keep the hook subscribed to an idle snapshot without starting network work.
50
+
51
+ ## useQoreStreamSnapshot
52
+
53
+ Use `useQoreStreamSnapshot` when the stream is created outside React and the component only needs a live snapshot.
54
+
55
+ ```tsx
56
+ import type { QoreStream } from '@qorejs/qore';
57
+ import { useQoreStreamSnapshot } from '@qorejs/react';
58
+
59
+ export function Transcript({ answer }: { answer: QoreStream<string, string> }) {
60
+ const snapshot = useQoreStreamSnapshot(answer, { initialValue: '' });
61
+
62
+ return <p>{snapshot.value}</p>;
63
+ }
64
+ ```
65
+
66
+ The returned object includes the stream value plus lifecycle fields such as `status`, `error`, `chunks`, `streaming`, `completed`, `failed`, `aborted`, `buffered`, and `dropped`.
67
+
68
+ ## useQoreSignalSelector
69
+
70
+ Use `useQoreSignalSelector` when a React component only needs one derived slice of a Qore signal. The selector keeps React renders focused on the value that component actually reads.
71
+
72
+ ```tsx
73
+ import type { QoreStream } from '@qorejs/qore';
74
+ import { useQoreSignalSelector } from '@qorejs/react';
75
+
76
+ function TokenCounter({ answer }: { answer: QoreStream<string, string> }) {
77
+ const tokenCount = useQoreSignalSelector(answer.chunks, (chunks) => chunks.length);
78
+ return <span>{tokenCount}</span>;
79
+ }
80
+ ```
81
+
82
+ Pass `isEqual` when the selected value is an object and you want to preserve the previous reference until the meaningful fields change.
83
+
84
+ ## useQoreSignal
85
+
86
+ Use `useQoreSignal` for any Qore readonly signal.
87
+
88
+ ```tsx
89
+ import type { ReadonlySignal } from '@qorejs/qore';
90
+ import { useQoreSignal } from '@qorejs/react';
91
+
92
+ export function Counter({ count }: { count: ReadonlySignal<number> }) {
93
+ const value = useQoreSignal(count);
94
+ return <span>{value}</span>;
95
+ }
96
+ ```
97
+
98
+ ## Safety Notes
99
+
100
+ Provider adapters are still intended for server-side or trusted runtimes. In browser React apps, stream from your own SSE or NDJSON endpoint instead of exposing provider API keys.
101
+
102
+ Keep dependency arrays honest. If the stream factory reads `prompt`, `model`, `conversationId`, or auth/session state, include those values in the dependency list.
@@ -0,0 +1,86 @@
1
+ # Runtime
2
+
3
+ The stream runtime is the core of Qore.
4
+
5
+ ## Lifecycle
6
+
7
+ Every `QoreStream` exposes readonly lifecycle signals:
8
+
9
+ ```js
10
+ answer.status(); // idle | pending | streaming | completed | failed | aborted
11
+ answer.error(); // Error | null
12
+ answer.chunkCount(); // number
13
+ answer.buffered(); // queued chunks
14
+ answer.dropped(); // dropped chunks
15
+ ```
16
+
17
+ Runtime-owned state is readonly from user code, so external callers cannot force inconsistent states.
18
+
19
+ ## Backpressure
20
+
21
+ ```js
22
+ const answer = stream.withBackpressure(source, {
23
+ interval: 16,
24
+ buffer: 8,
25
+ overflow: 'drop-oldest'
26
+ });
27
+ ```
28
+
29
+ Backpressure controls how quickly chunks commit into the signal and UI.
30
+
31
+ Overflow strategies:
32
+
33
+ - `wait`
34
+ - `drop-oldest`
35
+ - `drop-newest`
36
+ - `error`
37
+
38
+ ## Orchestration
39
+
40
+ Qore includes stream composition primitives for agent and realtime flows:
41
+
42
+ ```js
43
+ stream.merge([tokens, toolCalls, status]);
44
+ stream.concat([retrieve, summarize, format]);
45
+ stream.pipe(retrieve, [(docs) => summarize(docs), (summary) => format(summary)]);
46
+ stream.race([openai.chat(q), anthropic.chat(q)]);
47
+ stream.retryable(() => openai.chat(q), { maxRetries: 2 });
48
+ stream.switchMap(promptChanges, (prompt) => openai.chat(prompt));
49
+ ```
50
+
51
+ The composed result is still a stream signal.
52
+
53
+ ## Event Streams
54
+
55
+ Provider streams are only the transport boundary. Agent interfaces need a richer runtime surface: text tokens, tool calls, status updates, reasoning notes, diffs, artifacts, retries, and errors can all be modeled as typed events.
56
+
57
+ ```js
58
+ const events = stream.events(agent.run(task));
59
+
60
+ const markdown = events.select('text', {
61
+ seed: '',
62
+ reduce: (current, event) => current + event.text
63
+ });
64
+ const toolCalls = events.select('tool_call');
65
+ const status = events.select('status');
66
+ const diffs = events.select('diff', {
67
+ seed: '',
68
+ reduce: (current, event) => current + event.patch
69
+ });
70
+ ```
71
+
72
+ The full event timeline remains available through `events()`. Each selector is also a stream signal, so one UI region can render the timeline while another region renders only the accumulated markdown or diff.
73
+
74
+ A complete typed example lives in [`examples/agent-event-stream.ts`](../examples/agent-event-stream.ts). It projects one agent event timeline into markdown, status, tool-call, tool-result, diff, and artifact surfaces without creating separate state stores.
75
+
76
+ ## Abort
77
+
78
+ Streams can be aborted from the Qore stream object or from provider request options:
79
+
80
+ ```js
81
+ const controller = new AbortController();
82
+ const answer = stream(openai.chat('hello', { signal: controller.signal }));
83
+
84
+ controller.abort();
85
+ answer.abort();
86
+ ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@qorejs/qore",
3
- "version": "1.0.0",
4
- "description": "Qore is a streaming-response framework where stream becomes signal.",
3
+ "version": "1.0.2",
4
+ "description": "Qore is a reactive stream runtime for AI-native interfaces.",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",
7
7
  "types": "./dist/src/index.d.ts",
@@ -15,6 +15,8 @@
15
15
  "files": [
16
16
  "dist/src",
17
17
  "README.md",
18
+ "README.zh-CN.md",
19
+ "docs",
18
20
  "LICENSE"
19
21
  ],
20
22
  "sideEffects": false,
@@ -36,7 +38,9 @@
36
38
  "publish:preflight": "node ./scripts/publish-preflight.mjs",
37
39
  "publish:github": "npm publish --registry=https://npm.pkg.github.com",
38
40
  "publish:npm": "node ./scripts/publish-npm.mjs",
39
- "prepublishOnly": "node ./scripts/release-check.mjs"
41
+ "prepublishOnly": "node ./scripts/release-check.mjs",
42
+ "smoke:react-package": "node ./scripts/react-package-smoke.mjs",
43
+ "check:npm-access": "node ./scripts/check-npm-access.mjs"
40
44
  },
41
45
  "engines": {
42
46
  "node": ">=18.0.0"
@@ -72,6 +76,8 @@
72
76
  "devDependencies": {
73
77
  "@playwright/test": "^1.60.0",
74
78
  "@types/node": "^25.6.0",
79
+ "@types/react": "^19.2.17",
80
+ "react": "^19.2.7",
75
81
  "typescript": "^6.0.3"
76
82
  }
77
83
  }