@qorejs/qore 0.7.0 → 0.7.1
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/README.md +49 -48
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Qore
|
|
2
2
|
|
|
3
|
-
Qore
|
|
3
|
+
Qore is a streaming-response framework where `stream = signal`.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Instead of treating data as a snapshot, Qore treats it like a river. Tokens arrive piece by piece, and the UI should respond piece by piece too. No manual string accumulation. No scattered loading state. No partial rendering workaround layered on top of a snapshot-first mental model.
|
|
6
6
|
|
|
7
7
|
## Installation
|
|
8
8
|
|
|
@@ -16,9 +16,10 @@ npm i @qorejs/qore
|
|
|
16
16
|
|
|
17
17
|
## Core Idea
|
|
18
18
|
|
|
19
|
-
`stream`
|
|
19
|
+
`stream` is how data flows.
|
|
20
|
+
`signal` is how the UI reacts.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
In Qore, they are two sides of the same primitive:
|
|
22
23
|
|
|
23
24
|
```js
|
|
24
25
|
import { createOpenAI, h, stream, text } from '@qorejs/qore';
|
|
@@ -29,18 +30,18 @@ const answer = stream(openai.chat('hello'));
|
|
|
29
30
|
return h('div', {}, text(() => answer()));
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
Here, `answer` is all of the following at once:
|
|
33
34
|
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
35
|
+
- A read-only `signal`, so `answer()` returns the current accumulated value
|
|
36
|
+
- An `AsyncIterable`, so you can still use `for await...of`
|
|
37
|
+
- A lifecycle-aware streaming state, with `status()`, `streaming()`, `error()`, and `chunks()`
|
|
37
38
|
|
|
38
39
|
## Why Qore
|
|
39
40
|
|
|
40
|
-
- React
|
|
41
|
-
- SolidJS
|
|
42
|
-
- Vue
|
|
43
|
-
- Qore
|
|
41
|
+
- React treats streaming as a special case that needs extra machinery
|
|
42
|
+
- SolidJS has excellent signals, but no native stream primitive
|
|
43
|
+
- Vue has ergonomic refs, but stream handling still lives outside the core model
|
|
44
|
+
- Qore makes `stream = signal` the core API from the start
|
|
44
45
|
|
|
45
46
|
## Quick Start
|
|
46
47
|
|
|
@@ -48,15 +49,15 @@ return h('div', {}, text(() => answer()));
|
|
|
48
49
|
import { h, mount, stream, text } from '@qorejs/qore';
|
|
49
50
|
|
|
50
51
|
const answer = stream(async function* () {
|
|
51
|
-
yield '
|
|
52
|
-
yield '
|
|
53
|
-
yield '
|
|
52
|
+
yield 'stream';
|
|
53
|
+
yield ' = ';
|
|
54
|
+
yield 'signal';
|
|
54
55
|
}());
|
|
55
56
|
|
|
56
57
|
mount('#app', () => h('div', { className: 'answer' }, text(() => answer())));
|
|
57
58
|
```
|
|
58
59
|
|
|
59
|
-
|
|
60
|
+
This updates only the text node that depends on the stream. It does not re-render the whole tree.
|
|
60
61
|
|
|
61
62
|
## Providers
|
|
62
63
|
|
|
@@ -88,7 +89,7 @@ const answer = stream(anthropic.chat('Why should stream be signal?'));
|
|
|
88
89
|
|
|
89
90
|
### `createSSEAdapter(options?)`
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
If your backend already streams `text/event-stream`, Qore can adopt it directly:
|
|
92
93
|
|
|
93
94
|
```js
|
|
94
95
|
import { createSSEAdapter, stream } from '@qorejs/qore';
|
|
@@ -113,25 +114,25 @@ const provider = createSSEAdapter({
|
|
|
113
114
|
const answer = stream(provider.chat('hello'));
|
|
114
115
|
```
|
|
115
116
|
|
|
116
|
-
|
|
117
|
+
That makes `stream(provider.chat(...))` a general entry point instead of something tied to a single SDK.
|
|
117
118
|
|
|
118
119
|
## API Shape
|
|
119
120
|
|
|
120
121
|
### `stream(source, options?)`
|
|
121
122
|
|
|
122
|
-
|
|
123
|
+
By default, `stream(...)` accumulates chunks into a text signal:
|
|
123
124
|
|
|
124
125
|
```js
|
|
125
126
|
const answer = stream(openai.chat('hello'));
|
|
126
127
|
|
|
127
|
-
answer(); //
|
|
128
|
+
answer(); // current text
|
|
128
129
|
answer.status(); // idle | pending | streaming | completed | error | aborted
|
|
129
130
|
answer.streaming(); // boolean
|
|
130
|
-
answer.chunks(); //
|
|
131
|
-
await answer.ready; //
|
|
131
|
+
answer.chunks(); // raw chunks
|
|
132
|
+
await answer.ready; // wait for completion
|
|
132
133
|
```
|
|
133
134
|
|
|
134
|
-
|
|
135
|
+
If you need structured streams:
|
|
135
136
|
|
|
136
137
|
```js
|
|
137
138
|
const events = stream.list(eventSource);
|
|
@@ -148,17 +149,17 @@ const answer = stream.withBackpressure(openai.chat('hello'), {
|
|
|
148
149
|
});
|
|
149
150
|
```
|
|
150
151
|
|
|
151
|
-
|
|
152
|
+
Backpressure is not just a delay wrapper:
|
|
152
153
|
|
|
153
|
-
- `interval
|
|
154
|
-
- `buffer
|
|
155
|
-
- `overflow
|
|
154
|
+
- `interval`: the minimum spacing between chunk delivery into the signal and UI
|
|
155
|
+
- `buffer`: the maximum number of queued chunks before the UI catches up
|
|
156
|
+
- `overflow`: what to do when the buffer is full: `wait`, `drop-oldest`, `drop-newest`, or `error`
|
|
156
157
|
|
|
157
|
-
|
|
158
|
+
You can also observe stream pressure directly:
|
|
158
159
|
|
|
159
160
|
```js
|
|
160
|
-
answer.buffered(); //
|
|
161
|
-
answer.dropped(); //
|
|
161
|
+
answer.buffered(); // how many chunks are queued right now
|
|
162
|
+
answer.dropped(); // how many chunks were dropped by the overflow policy
|
|
162
163
|
```
|
|
163
164
|
|
|
164
165
|
### `signal`, `computed`, `effect`
|
|
@@ -172,13 +173,13 @@ const length = computed(() => answer().length);
|
|
|
172
173
|
|
|
173
174
|
### `response`
|
|
174
175
|
|
|
175
|
-
`response`
|
|
176
|
+
`response` still exists, but it is closer to a lower-level state machine escape hatch for custom reducers and aggregators.
|
|
176
177
|
|
|
177
|
-
|
|
178
|
+
If your goal is to pipe a stream directly into the UI, prefer `stream(...)`.
|
|
178
179
|
|
|
179
180
|
## Demos
|
|
180
181
|
|
|
181
|
-
|
|
182
|
+
The repository includes a landing page and a focused streaming demo:
|
|
182
183
|
|
|
183
184
|
- [Landing Page Source](https://github.com/qorejs/qore/blob/main/index.html)
|
|
184
185
|
- [Homepage Logic](https://github.com/qorejs/qore/blob/main/examples/showcase.js)
|
|
@@ -187,7 +188,7 @@ const length = computed(() => answer().length);
|
|
|
187
188
|
- [Focused Chat Logic](https://github.com/qorejs/qore/blob/main/examples/qore-chat.js)
|
|
188
189
|
- [React Compare](https://github.com/qorejs/qore/blob/main/examples/react-chat.jsx)
|
|
189
190
|
|
|
190
|
-
|
|
191
|
+
For a local preview:
|
|
191
192
|
|
|
192
193
|
```bash
|
|
193
194
|
git clone git@github.com:qorejs/qore.git
|
|
@@ -195,19 +196,19 @@ cd qore
|
|
|
195
196
|
python3 -m http.server 4173
|
|
196
197
|
```
|
|
197
198
|
|
|
198
|
-
|
|
199
|
+
Then open [http://127.0.0.1:4173/](http://127.0.0.1:4173/).
|
|
199
200
|
|
|
200
201
|
## Package Boundary
|
|
201
202
|
|
|
202
|
-
Qore
|
|
203
|
+
Qore does not ship a built-in catalog of buttons, dialogs, tabs, or other UI primitives.
|
|
203
204
|
|
|
204
|
-
|
|
205
|
+
The core package does only three things:
|
|
205
206
|
|
|
206
|
-
-
|
|
207
|
-
-
|
|
208
|
-
-
|
|
207
|
+
- Move streams into state
|
|
208
|
+
- Move state into the UI
|
|
209
|
+
- Keep the whole process finely reactive
|
|
209
210
|
|
|
210
|
-
|
|
211
|
+
Anything that does not serve `streaming response` belongs in an experimental layer or a separate package.
|
|
211
212
|
|
|
212
213
|
## Testing
|
|
213
214
|
|
|
@@ -215,14 +216,14 @@ Qore 核心包不内置 Button、Dialog、Tabs 这类 UI primitives。
|
|
|
215
216
|
npm test
|
|
216
217
|
```
|
|
217
218
|
|
|
218
|
-
|
|
219
|
+
The current test suite covers:
|
|
219
220
|
|
|
220
|
-
- signal
|
|
221
|
-
- stream = signal
|
|
222
|
-
- response
|
|
223
|
-
- OpenAI
|
|
221
|
+
- `signal`, `computed`, and `effect`
|
|
222
|
+
- The core `stream = signal` behavior
|
|
223
|
+
- `response` interoperability with async iterables
|
|
224
|
+
- OpenAI, Anthropic, and generic SSE adapters
|
|
224
225
|
|
|
225
226
|
## Roadmap
|
|
226
227
|
|
|
227
|
-
-
|
|
228
|
-
-
|
|
228
|
+
- Tighten the hydration model around server-streamed rendering
|
|
229
|
+
- Publish repeatable benchmarks that compare Qore with React and the Vercel AI SDK
|