@rebon/cli-linux-x64 1.2.0 → 1.4.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.
@@ -1,204 +0,0 @@
1
- // Minimal dsh-compatible `ctx.web` seat for the composition host (P2.7,
2
- // docs/dsh-web-assembly.md).
3
- //
4
- // API shape follows dsh packages/web/web verbatim: providers register with
5
- // `ctx.web.registerSearchProvider/registerFetchProvider` (duplicate ids
6
- // throw WEB_DUPLICATE_PROVIDER; the exact disposer comes back), and
7
- // `search`/`fetch` resolve their provider at EXECUTION time with dsh's
8
- // five-state rules — a configured id wins or fails loudly (never falls
9
- // back), otherwise exactly one usable provider auto-selects. The seat
10
- // enforces `maxResults` truncation on search results (capSources).
11
- //
12
- // Deployment default: the `rebon` builtin provider (backed by the R5
13
- // invokeTool bridge onto rebon's own WebSearch/WebFetch) is always
14
- // registered, and the configured id DEFAULTS to `"rebon"` — feeding the
15
- // same config field dsh uses (`bootConfig().web.searchProvider` /
16
- // `.fetchProvider`, i.e. config.json's `web` section), never a hidden
17
- // priority chain. So plugin providers take over only when configured, and
18
- // the multi-provider AMBIGUOUS state is unreachable unless the default is
19
- // explicitly cleared.
20
- //
21
- // Registrations are mirrored to the Rust seat via
22
- // `web/provider-registered` / `web/provider-unregistered` kernel events
23
- // (`available` is a registration-time snapshot — a static composition's
24
- // config does not change under it; documented v1 semantics), and each
25
- // plugin provider is served back to Rust dispatch through the shared serve
26
- // pump under the reserved target `web:<kind>:<id>`.
27
- import { Service } from 'cordis';
28
- import { bootConfig, emit, invokeTool } from 'rebon';
29
- import { WebError } from './shims/dsh-web.js';
30
- import { ensureServePump, registerServeTarget } from './serve-dispatch.js';
31
-
32
- /** dsh WebRuntime.resolveProvider, transcribed. */
33
- function resolveProvider(configuredId, providers) {
34
- if (configuredId !== undefined) {
35
- const provider = providers.get(configuredId);
36
- if (!provider) {
37
- throw new WebError(
38
- `configured web provider "${configuredId}" is not registered`,
39
- 'WEB_PROVIDER_CONFIGURED_MISSING',
40
- );
41
- }
42
- if (!provider.available()) {
43
- throw new WebError(
44
- `configured web provider "${configuredId}" is registered but unavailable`,
45
- 'WEB_PROVIDER_CONFIGURED_UNAVAILABLE',
46
- );
47
- }
48
- return provider;
49
- }
50
- const usable = [...providers.values()].filter((provider) => {
51
- try {
52
- return !!provider.available();
53
- } catch {
54
- return false;
55
- }
56
- });
57
- if (usable.length === 0) {
58
- throw new WebError('no usable web provider is registered', 'WEB_PROVIDER_UNAVAILABLE');
59
- }
60
- if (usable.length > 1) {
61
- const ids = usable.map((provider) => provider.id).join(', ');
62
- throw new WebError(
63
- `multiple usable web providers are registered (${ids}); configure one explicitly`,
64
- 'WEB_PROVIDER_AMBIGUOUS',
65
- );
66
- }
67
- return usable[0];
68
- }
69
-
70
- /** dsh capSources: enforce `maxResults` on the way back. */
71
- function capSources(result, maxResults) {
72
- if (maxResults === undefined || (result.sources?.length ?? 0) <= maxResults) return result;
73
- return { ...result, sources: result.sources.slice(0, maxResults), truncated: true };
74
- }
75
-
76
- /**
77
- * The rebon builtin search provider: rides the R5 invokeTool bridge onto
78
- * rebon's WebSearch tool (read-only, so no grant is needed) and maps the
79
- * `{query, answer, results}` contract into dsh's result vocabulary.
80
- */
81
- const rebonBuiltinSearch = {
82
- id: 'rebon',
83
- available: () => true,
84
- async search(request, _signal) {
85
- const out = await invokeTool('WebSearch', { query: String(request?.query ?? '') });
86
- const sources = (out?.results ?? [])
87
- .map((entry) => ({
88
- url: String(entry?.url ?? ''),
89
- ...(entry?.title ? { title: String(entry.title) } : {}),
90
- ...(entry?.snippet ? { snippet: String(entry.snippet) } : {}),
91
- }))
92
- .filter((source) => source.url.length > 0);
93
- return {
94
- ...(out?.answer ? { content: String(out.answer) } : {}),
95
- sources,
96
- truncated: false,
97
- };
98
- },
99
- };
100
-
101
- /**
102
- * The rebon builtin fetch provider over rebon's WebFetch tool. The tool
103
- * returns extracted text, not raw transport facts, so `statusCode` is the
104
- * 200 the extraction implies and the body is `text` — a documented v1
105
- * approximation, not a transport claim.
106
- */
107
- const rebonBuiltinFetch = {
108
- id: 'rebon',
109
- available: () => true,
110
- async fetch(request, _signal) {
111
- const out = await invokeTool('WebFetch', { url: String(request?.url ?? '') });
112
- const content =
113
- typeof out === 'string' ? out : String(out?.content ?? out?.text ?? JSON.stringify(out));
114
- return {
115
- url: String(request?.url ?? ''),
116
- statusCode: 200,
117
- body: { kind: 'text', content },
118
- truncated: false,
119
- };
120
- },
121
- };
122
-
123
- export default class RebonWebRuntime extends Service {
124
- constructor(ctx, options) {
125
- super(ctx, 'web');
126
- // Per-loop hosts keep provider registrations off the process event
127
- // plane (llm-runtime same rule).
128
- this.announce = options?.announce !== false;
129
- const config = bootConfig()?.web ?? {};
130
- const configured = (value) =>
131
- typeof value === 'string' && value.trim().length > 0 ? value.trim() : 'rebon';
132
- this.searchProviderId = configured(config.searchProvider);
133
- this.fetchProviderId = configured(config.fetchProvider);
134
- this.searchProviders = new Map([['rebon', rebonBuiltinSearch]]);
135
- this.fetchProviders = new Map([['rebon', rebonBuiltinFetch]]);
136
- ensureServePump();
137
- }
138
-
139
- registerSearchProvider(provider) {
140
- return this._register(this.searchProviders, 'search', provider);
141
- }
142
-
143
- registerFetchProvider(provider) {
144
- return this._register(this.fetchProviders, 'fetch', provider);
145
- }
146
-
147
- _register(store, kind, provider) {
148
- if (typeof provider?.id !== 'string' || provider.id.length === 0) {
149
- throw new TypeError('a web provider must declare a non-empty string `id`');
150
- }
151
- if (store.has(provider.id)) {
152
- throw new WebError(
153
- `a web provider with id "${provider.id}" is already registered`,
154
- 'WEB_DUPLICATE_PROVIDER',
155
- );
156
- }
157
- const runtime = this;
158
- // Caller-fork RAII (Service proxy binds this.ctx to the registrant):
159
- // plugin disposal removes the provider, the kernel mirror, and the
160
- // serve target together.
161
- return this.ctx.effect(() => {
162
- store.set(provider.id, provider);
163
- let available = false;
164
- try {
165
- available = !!provider.available();
166
- } catch {}
167
- const disposeServe = registerServeTarget(
168
- `web:${kind}:${provider.id}`,
169
- (input, signal) => runtime._serve(kind, provider, input, signal),
170
- );
171
- if (runtime.announce) emit('web/provider-registered', { kind, id: provider.id, available });
172
- return () => {
173
- disposeServe();
174
- store.delete(provider.id);
175
- if (runtime.announce) emit('web/provider-unregistered', { kind, id: provider.id });
176
- };
177
- });
178
- }
179
-
180
- /** Rust-dispatched execution of one plugin provider (seat rules applied). */
181
- async _serve(kind, provider, input, signal) {
182
- if (kind === 'search') {
183
- const request = {
184
- query: String(input?.query ?? ''),
185
- ...(input?.maxResults !== undefined ? { maxResults: input.maxResults } : {}),
186
- };
187
- return capSources(await provider.search(request, signal), request.maxResults);
188
- }
189
- return provider.fetch({ url: String(input?.url ?? '') }, signal);
190
- }
191
-
192
- /** dsh consumer API: run one search through the selected provider. */
193
- async search(request, signal) {
194
- const provider = resolveProvider(this.searchProviderId, this.searchProviders);
195
- const result = await provider.search(request, signal);
196
- return capSources(result, request?.maxResults);
197
- }
198
-
199
- /** dsh consumer API: retrieve one URL through the selected provider. */
200
- async fetch(request, signal) {
201
- const provider = resolveProvider(this.fetchProviderId, this.fetchProviders);
202
- return provider.fetch(request, signal);
203
- }
204
- }