@deepwatch/dsh-client-settings 0.1.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.
- package/LICENSE +21 -0
- package/README.md +82 -0
- package/lib/client/binding-state.d.ts +334 -0
- package/lib/client/binding-state.js +543 -0
- package/lib/client/binding-state.js.map +1 -0
- package/lib/client/chat-gate.d.ts +100 -0
- package/lib/client/chat-gate.js +141 -0
- package/lib/client/chat-gate.js.map +1 -0
- package/lib/client/components.d.ts +194 -0
- package/lib/client/components.js +273 -0
- package/lib/client/components.js.map +1 -0
- package/lib/client/index.d.ts +35 -0
- package/lib/client/index.js +273 -0
- package/lib/client/index.js.map +1 -0
- package/lib/client/onboarding.d.ts +28 -0
- package/lib/client/onboarding.js +31 -0
- package/lib/client/onboarding.js.map +1 -0
- package/lib/client/readiness.d.ts +36 -0
- package/lib/client/readiness.js +207 -0
- package/lib/client/readiness.js.map +1 -0
- package/lib/client/role-bindings.d.ts +118 -0
- package/lib/client/role-bindings.js +211 -0
- package/lib/client/role-bindings.js.map +1 -0
- package/lib/client.js +3888 -0
- package/lib/client.js.map +1 -0
- package/lib/index.d.ts +13 -0
- package/lib/index.js +13 -0
- package/lib/index.js.map +1 -0
- package/lib/ocr-measured.d.ts +27 -0
- package/lib/ocr-measured.js +66 -0
- package/lib/ocr-measured.js.map +1 -0
- package/lib/providers.d.ts +26 -0
- package/lib/providers.js +26 -0
- package/lib/providers.js.map +1 -0
- package/package.json +83 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 oxbshw
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# @deepwatch/dsh-client-settings
|
|
2
|
+
|
|
3
|
+
Browser half: the Watch Technology & Capability Center — role bindings, engines, sources, memory, verification, diagnostics, about
|
|
4
|
+
|
|
5
|
+
Part of **DeepWatch** — the agent workspace built on the official
|
|
6
|
+
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)
|
|
7
|
+
and powered by [Watch Skill](https://github.com/oxbshw/watch-skill) for perception, evidence, memory and
|
|
8
|
+
independent verification.
|
|
9
|
+
|
|
10
|
+
> **Browser half — runs in the workspace UI.**
|
|
11
|
+
> Composed by the bundle and loaded by the DSH client loader.
|
|
12
|
+
|
|
13
|
+
## Exports
|
|
14
|
+
|
|
15
|
+
- `@deepwatch/dsh-client-settings`
|
|
16
|
+
- `@deepwatch/dsh-client-settings/client`
|
|
17
|
+
- `@deepwatch/dsh-client-settings/components`
|
|
18
|
+
|
|
19
|
+
## Peers
|
|
20
|
+
|
|
21
|
+
Provided by the host rather than installed here:
|
|
22
|
+
|
|
23
|
+
- `@deepseek-ai/cordis@4.0.2`
|
|
24
|
+
- `@deepseek-ai/dsh-client-ui-primitives@0.1.1-rc.2`
|
|
25
|
+
- `react@^18.2.0`
|
|
26
|
+
|
|
27
|
+
## Install
|
|
28
|
+
|
|
29
|
+
> **Not on npm yet.** Nothing exists under the `@deepwatch` scope. This
|
|
30
|
+
> package is published for the first time by the `deepwatch-v0.1.0`
|
|
31
|
+
> release; until then the command below resolves nothing, and
|
|
32
|
+
> [the workspace README](https://github.com/oxbshw/watch-skill/tree/main/workspace#readme) has the path
|
|
33
|
+
> that works from a checkout.
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm install @deepwatch/dsh-client-settings
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Rarely on its own. [`@deepwatch/dsh-bundle`](https://github.com/oxbshw/watch-skill/tree/main/workspace/packages/watch/bundle#readme)
|
|
40
|
+
composes this package with the rest of DeepWatch and is what a profile
|
|
41
|
+
normally depends on; installing this one directly is for embedding a
|
|
42
|
+
single piece in a composition you control.
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Node `^22.19.0 || >=24.0.0`
|
|
47
|
+
- The peers above, supplied by the host composition
|
|
48
|
+
|
|
49
|
+
## Stability
|
|
50
|
+
|
|
51
|
+
`0.1.0` — a stable release.
|
|
52
|
+
|
|
53
|
+
Stable means tested, documented and supported — not 1.0. This is a
|
|
54
|
+
pre-1.0 line, and semantic versioning gives `0.x` no compatibility
|
|
55
|
+
guarantee across minor versions: **a `0.MINOR` bump may change or remove
|
|
56
|
+
surface, and a patch will not.** Depend on it with a tilde range
|
|
57
|
+
(`~0.1.0`) if you want that difference enforced by your lockfile
|
|
58
|
+
rather than by a changelog. The usual major-version promise starts at 1.0.
|
|
59
|
+
|
|
60
|
+
## Side effects
|
|
61
|
+
|
|
62
|
+
Importing a module from this package evaluates no side effects, so a
|
|
63
|
+
bundler may drop what a build does not use. Mounting it in a host is a
|
|
64
|
+
separate matter: what it then reads or writes is governed by the
|
|
65
|
+
workspace boundary and the host's permissions, not by this flag.
|
|
66
|
+
|
|
67
|
+
## Where this fits
|
|
68
|
+
|
|
69
|
+
The Technology & Capability Center: role bindings, engines, sources, memory, verification and diagnostics. This is the screen that says what is ready and what is missing.
|
|
70
|
+
|
|
71
|
+
The twenty packages and how they compose:
|
|
72
|
+
[the package map](https://github.com/oxbshw/watch-skill/blob/main/workspace/docs/packages.md).
|
|
73
|
+
Running DeepWatch, and the gates a change has to pass:
|
|
74
|
+
[the workspace README](https://github.com/oxbshw/watch-skill/tree/main/workspace#readme).
|
|
75
|
+
|
|
76
|
+
## Attribution
|
|
77
|
+
|
|
78
|
+
Built on DeepSeek Harness · Powered by Watch Skill
|
|
79
|
+
|
|
80
|
+
DeepWatch and Watch Skill are independent projects and are not affiliated
|
|
81
|
+
with or endorsed by DeepSeek. MIT licensed; third-party notices are in
|
|
82
|
+
[THIRD_PARTY_NOTICES.md](https://github.com/oxbshw/watch-skill/blob/main/workspace/THIRD_PARTY_NOTICES.md).
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The browser's view of what is configured, assembled from four Host answers.
|
|
3
|
+
*
|
|
4
|
+
* A person saved an OpenRouter credential, saw a green dot and the words
|
|
5
|
+
* "Saved openrouter.", and reasonably concluded the product was ready. It was
|
|
6
|
+
* not: no model had been chosen and nothing had been assigned to anything. The
|
|
7
|
+
* dot was answering "is a credential stored?" while the reader was asking "can
|
|
8
|
+
* I send a message?", and those turn out to be four separate questions.
|
|
9
|
+
*
|
|
10
|
+
* So this store never derives readiness itself. It gathers the four facts —
|
|
11
|
+
* from `llm.providers`, `llm.models`, `credentials.describe` and the stored
|
|
12
|
+
* bindings in `settings.describe` — and hands them to `roleReadiness`, which
|
|
13
|
+
* is the only thing in this product allowed to answer "ready". A surface that
|
|
14
|
+
* wanted to shade a dot green would have to go through the same gate.
|
|
15
|
+
*
|
|
16
|
+
* **Nothing here contacts a provider.** Opening a settings page must not spend
|
|
17
|
+
* somebody's money or rate budget, so reachability stays `unknown` until a
|
|
18
|
+
* person asks for a check. That is why a freshly saved credential reads
|
|
19
|
+
* "Credential saved · not yet assigned" rather than a claim about whether it
|
|
20
|
+
* works: the honest state after a save is *stored*, and the product says so.
|
|
21
|
+
*
|
|
22
|
+
* **No value crosses this boundary.** `credentials.describe` is structurally
|
|
23
|
+
* value-free — it answers `configured`, `source`, `writable` and has no slot
|
|
24
|
+
* for a value — and the binding this store writes holds a reference the Host
|
|
25
|
+
* resolves. There is nowhere in this file for a key to be, which is the
|
|
26
|
+
* property that makes the store safe to render, log and screenshot.
|
|
27
|
+
*
|
|
28
|
+
* @module @deepwatch/dsh-client-settings/binding-state
|
|
29
|
+
*/
|
|
30
|
+
import type { BindableRole, ProviderCredentialStatus, ProviderReachability, RoleReadiness, WatchBindings } from '@deepwatch/dsh-contracts';
|
|
31
|
+
/**
|
|
32
|
+
* Upstream's own settings section for the selection a new session starts with.
|
|
33
|
+
*
|
|
34
|
+
* Spelled here rather than imported: `AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE`
|
|
35
|
+
* lives in a Host package, and a browser bundle that imported it would carry
|
|
36
|
+
* the Harness's server-side settings machinery to learn one string.
|
|
37
|
+
* `tests/binding-flow.test.mjs` holds it to the value the pinned baseline
|
|
38
|
+
* composes.
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_MODEL_NAMESPACE = "agent-default-model";
|
|
41
|
+
/**
|
|
42
|
+
* The RPC envelope, narrowed to what a caller reads.
|
|
43
|
+
*
|
|
44
|
+
* Declared structurally rather than imported, which is the same choice
|
|
45
|
+
* `./index.tsx` makes for the slot service. A browser bundle that imported the
|
|
46
|
+
* Host's contract package for four method signatures would carry the whole
|
|
47
|
+
* gateway's types to describe calls it makes by name anyway.
|
|
48
|
+
*/
|
|
49
|
+
type Rpc<T> = {
|
|
50
|
+
readonly result: {
|
|
51
|
+
ok: true;
|
|
52
|
+
value: T;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
error: {
|
|
56
|
+
code: string;
|
|
57
|
+
message: string;
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
/** One namespace as the settings domain describes it. */
|
|
62
|
+
export interface NamespaceView {
|
|
63
|
+
readonly ns: string;
|
|
64
|
+
readonly value: unknown;
|
|
65
|
+
readonly user?: unknown;
|
|
66
|
+
readonly revision: number;
|
|
67
|
+
}
|
|
68
|
+
/** One provider route, as the provider directory describes it. */
|
|
69
|
+
export interface ProviderView {
|
|
70
|
+
readonly provider: string;
|
|
71
|
+
readonly displayName: string;
|
|
72
|
+
readonly settingsNs: string;
|
|
73
|
+
readonly settingsPath: readonly string[];
|
|
74
|
+
/** Whether an adapter currently serves the route. */
|
|
75
|
+
readonly active: boolean;
|
|
76
|
+
}
|
|
77
|
+
/** One model a provider advertised. */
|
|
78
|
+
export interface CatalogModel {
|
|
79
|
+
readonly id: string;
|
|
80
|
+
readonly name: string;
|
|
81
|
+
readonly description?: string;
|
|
82
|
+
}
|
|
83
|
+
/** One provider and the models it advertised. */
|
|
84
|
+
export interface ModelGroup {
|
|
85
|
+
readonly id: string;
|
|
86
|
+
readonly name: string;
|
|
87
|
+
readonly models: readonly CatalogModel[];
|
|
88
|
+
}
|
|
89
|
+
/** What the Host will answer about a credential. Never a value. */
|
|
90
|
+
export interface CredentialView {
|
|
91
|
+
readonly configured: boolean;
|
|
92
|
+
readonly source?: string;
|
|
93
|
+
readonly writable: boolean;
|
|
94
|
+
}
|
|
95
|
+
/** The Host methods this store calls, by the names the gateway gives them. */
|
|
96
|
+
export interface HostApi {
|
|
97
|
+
readonly settings: {
|
|
98
|
+
describe(payload: Record<string, never>): Promise<Rpc<{
|
|
99
|
+
writable: boolean;
|
|
100
|
+
namespaces: readonly NamespaceView[];
|
|
101
|
+
}>>;
|
|
102
|
+
replace(payload: {
|
|
103
|
+
ns: string;
|
|
104
|
+
section: object;
|
|
105
|
+
expectedRevision?: number;
|
|
106
|
+
}): Promise<Rpc<NamespaceView>>;
|
|
107
|
+
};
|
|
108
|
+
readonly llm: {
|
|
109
|
+
providers(payload: Record<string, never>): Promise<Rpc<{
|
|
110
|
+
providers: readonly ProviderView[];
|
|
111
|
+
}>>;
|
|
112
|
+
models(payload: Record<string, never>): Promise<Rpc<{
|
|
113
|
+
groups: readonly ModelGroup[];
|
|
114
|
+
failures: readonly {
|
|
115
|
+
id: string;
|
|
116
|
+
message: string;
|
|
117
|
+
}[];
|
|
118
|
+
}>>;
|
|
119
|
+
};
|
|
120
|
+
readonly credentials: {
|
|
121
|
+
describe(payload: {
|
|
122
|
+
refs: string[];
|
|
123
|
+
}): Promise<Rpc<{
|
|
124
|
+
credentials: Record<string, CredentialView>;
|
|
125
|
+
}>>;
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* The identity a provider test result belongs to.
|
|
130
|
+
*
|
|
131
|
+
* Provider and model alone are not enough. Rebinding a role to a route served
|
|
132
|
+
* through a different credential must not inherit the previous verdict — that
|
|
133
|
+
* is the same "saved means working" claim this whole file exists to remove,
|
|
134
|
+
* wearing a route it was never asked about. So the credential *reference* is
|
|
135
|
+
* part of the key.
|
|
136
|
+
*
|
|
137
|
+
* What it deliberately cannot see: a value rotated behind a reference that
|
|
138
|
+
* did not change. No credential value crosses this boundary, so the browser
|
|
139
|
+
* half has nothing to compare. A result therefore lives only as long as the
|
|
140
|
+
* session that produced it, and is never persisted or restored — an untested
|
|
141
|
+
* binding after a reload reads as untested, which is the truthful answer.
|
|
142
|
+
*/
|
|
143
|
+
export declare function providerTestKey(provider: string, model: string, credentialRef: string | null): string;
|
|
144
|
+
/** Provider-neutral result of the explicit, user-triggered one-token test. */
|
|
145
|
+
export interface ProviderTestFacts {
|
|
146
|
+
readonly provider: string;
|
|
147
|
+
readonly model: string;
|
|
148
|
+
readonly ok: boolean;
|
|
149
|
+
readonly credential: 'configured_unverified' | 'verified' | 'rejected';
|
|
150
|
+
readonly reachability: Exclude<ProviderReachability, 'unknown'>;
|
|
151
|
+
readonly message: string;
|
|
152
|
+
}
|
|
153
|
+
export type ProviderTester = (provider: string, model: string, signal: AbortSignal) => Promise<ProviderTestFacts>;
|
|
154
|
+
/** The Host's own verdict on one route, and why, when it is not ready. */
|
|
155
|
+
export interface RouteReadinessFacts {
|
|
156
|
+
readonly proved: boolean;
|
|
157
|
+
readonly reason: 'proved' | 'never_tested' | 'configuration_changed' | 'unreadable';
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Ask the Host whether it would serve a route, without spending anything.
|
|
161
|
+
*
|
|
162
|
+
* Optional, because a deployment may mount this panel against a Host without
|
|
163
|
+
* the read plane. Absent, the tab falls back to its own memory of the tests it
|
|
164
|
+
* ran — which is what this exists to stop being the only answer, and is still
|
|
165
|
+
* better than refusing to draw the screen.
|
|
166
|
+
*/
|
|
167
|
+
export type RouteReadinessReader = (provider: string, model: string, signal: AbortSignal) => Promise<RouteReadinessFacts>;
|
|
168
|
+
/** One provider, with everything a setup screen needs to talk about it. */
|
|
169
|
+
export interface ProviderRow {
|
|
170
|
+
readonly provider: string;
|
|
171
|
+
readonly displayName: string;
|
|
172
|
+
/** Whether an adapter serves the route right now. */
|
|
173
|
+
readonly active: boolean;
|
|
174
|
+
/** The opaque handle the Host resolves a credential through. Never a value. */
|
|
175
|
+
readonly credentialRef: string | null;
|
|
176
|
+
readonly credential: ProviderCredentialStatus;
|
|
177
|
+
/** Models the provider advertised, empty when it advertised none. */
|
|
178
|
+
readonly models: readonly CatalogModel[];
|
|
179
|
+
/** Why the catalogue is empty, when the provider said. */
|
|
180
|
+
readonly catalogError: string | null;
|
|
181
|
+
}
|
|
182
|
+
/** One role, its stored decision, and whether that decision can run. */
|
|
183
|
+
export interface RoleRow {
|
|
184
|
+
readonly role: BindableRole;
|
|
185
|
+
readonly provider: string | null;
|
|
186
|
+
readonly model: string | null;
|
|
187
|
+
readonly readiness: RoleReadiness;
|
|
188
|
+
}
|
|
189
|
+
/** Everything a binding surface reads. */
|
|
190
|
+
export interface BindingSnapshot {
|
|
191
|
+
readonly status: 'idle' | 'loading' | 'ready' | 'error';
|
|
192
|
+
/** A message for the reader when the Host could not be asked. */
|
|
193
|
+
readonly error: string | null;
|
|
194
|
+
/** False when the settings document cannot be written here. */
|
|
195
|
+
readonly writable: boolean;
|
|
196
|
+
readonly providers: readonly ProviderRow[];
|
|
197
|
+
readonly roles: readonly RoleRow[];
|
|
198
|
+
/** The stored document, for a surface that needs the raw decision. */
|
|
199
|
+
readonly bindings: WatchBindings;
|
|
200
|
+
/** True while a write is in flight, so a form can disable itself. */
|
|
201
|
+
readonly saving: boolean;
|
|
202
|
+
readonly testingRole: BindableRole | null;
|
|
203
|
+
readonly testMessage: string | null;
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The credential reference a provider's own settings section names.
|
|
207
|
+
*
|
|
208
|
+
* Walked out of the described value rather than asked for separately: the
|
|
209
|
+
* settings domain already returns each namespace's resolved value, and
|
|
210
|
+
* `apiKeyEnv` is a field in it. The walk is plain property access because the
|
|
211
|
+
* described value is plain JSON — the secret slots have already been removed
|
|
212
|
+
* by the seam, which is what makes reading this safe.
|
|
213
|
+
*/
|
|
214
|
+
export declare function credentialRefOf(view: NamespaceView | undefined, path: readonly string[]): string | null;
|
|
215
|
+
/**
|
|
216
|
+
* What is known about a provider's credential.
|
|
217
|
+
*
|
|
218
|
+
* `configured_unverified` rather than `verified` is the whole point. The Host
|
|
219
|
+
* can say a value resolves; only a provider can say it works, and nothing here
|
|
220
|
+
* has asked one. Calling a stored credential verified is the claim that sent a
|
|
221
|
+
* prompt to a provider nobody had configured.
|
|
222
|
+
*/
|
|
223
|
+
export declare function credentialStatusOf(ref: string | null, described: Record<string, CredentialView>, readable: boolean): ProviderCredentialStatus;
|
|
224
|
+
/** Everything known about one role, folded through the single readiness gate. */
|
|
225
|
+
export declare function roleRowOf(role: BindableRole, bindings: WatchBindings, providers: readonly ProviderRow[], tests?: ReadonlyMap<string, ProviderTestFacts>): RoleRow;
|
|
226
|
+
/**
|
|
227
|
+
* The binding store, shaped for `useSyncExternalStore`.
|
|
228
|
+
*
|
|
229
|
+
* Deliberately a plain object with `subscribe`/`getSnapshot` rather than a
|
|
230
|
+
* framework store: this package's browser half is loaded into somebody else's
|
|
231
|
+
* React tree, and bringing a state library into a plugin bundle to hold six
|
|
232
|
+
* fields is how a distribution ends up shipping two of them.
|
|
233
|
+
*/
|
|
234
|
+
export declare class BindingStore {
|
|
235
|
+
private readonly api;
|
|
236
|
+
private readonly providerTester?;
|
|
237
|
+
private readonly readinessReader?;
|
|
238
|
+
private snapshot;
|
|
239
|
+
private readonly listeners;
|
|
240
|
+
/** Guards against a slow load landing after a newer one. */
|
|
241
|
+
private generation;
|
|
242
|
+
private revision;
|
|
243
|
+
private defaultRevision;
|
|
244
|
+
private readonly providerTests;
|
|
245
|
+
private providerTestAbort;
|
|
246
|
+
constructor(api: HostApi, providerTester?: ProviderTester | undefined, readinessReader?: RouteReadinessReader | undefined);
|
|
247
|
+
/**
|
|
248
|
+
* Replace what this tab believes about tested routes with what the Host says.
|
|
249
|
+
*
|
|
250
|
+
* The browser used to be the only place a provider-test verdict lived, and a
|
|
251
|
+
* tab cannot see a Host restart, an edit made in another tab, or a key
|
|
252
|
+
* rotated behind a reference that did not change. It drew a tested badge over
|
|
253
|
+
* routes the Host had already stopped being willing to serve, and the
|
|
254
|
+
* composer that badge unlocks opened onto a refusal.
|
|
255
|
+
*
|
|
256
|
+
* So the Host is asked, per bound route, and its answer wins in both
|
|
257
|
+
* directions: a route it still proves is tested even in a tab that has just
|
|
258
|
+
* been reloaded and ran no test, and a route it no longer proves stops being
|
|
259
|
+
* tested here the moment this is read.
|
|
260
|
+
*/
|
|
261
|
+
private reconcileReadiness;
|
|
262
|
+
/** @returns the current snapshot; stable between changes. */
|
|
263
|
+
getSnapshot: () => BindingSnapshot;
|
|
264
|
+
/** @param listener - called after every change. @returns the unsubscriber. */
|
|
265
|
+
subscribe: (listener: () => void) => (() => void);
|
|
266
|
+
private publish;
|
|
267
|
+
/**
|
|
268
|
+
* Ask the Host everything, and fold it into one snapshot.
|
|
269
|
+
*
|
|
270
|
+
* The three reads run together because they are independent and a settings
|
|
271
|
+
* page that took three round trips in series felt broken on a slow link.
|
|
272
|
+
* Their failures are not equal, though: providers and settings are the page,
|
|
273
|
+
* so losing either is an error, while a credential describe that fails
|
|
274
|
+
* downgrades those providers to `inaccessible` and leaves the rest readable.
|
|
275
|
+
*/
|
|
276
|
+
load(): Promise<void>;
|
|
277
|
+
/**
|
|
278
|
+
* Write the Harness selection only when it disagrees with the binding.
|
|
279
|
+
*
|
|
280
|
+
* Guarded on disagreement because this runs on every load: rewriting an
|
|
281
|
+
* already-correct section would bump its revision, invalidate every other
|
|
282
|
+
* open editor's `expectedRevision`, and turn a read into a source of write
|
|
283
|
+
* conflicts.
|
|
284
|
+
*/
|
|
285
|
+
private reconcileDefaultSelection;
|
|
286
|
+
/**
|
|
287
|
+
* Bind one role to one provider and model, and persist the decision.
|
|
288
|
+
*
|
|
289
|
+
* `replace` rather than `update`, because unbinding has to be expressible:
|
|
290
|
+
* a merge cannot remove a key, and a role that could be added but not
|
|
291
|
+
* removed is a role somebody is stuck with. The whole document is rewritten
|
|
292
|
+
* from the snapshot the caller is looking at, and `expectedRevision` is what
|
|
293
|
+
* turns a concurrent edit into a refusal rather than a silent overwrite.
|
|
294
|
+
*/
|
|
295
|
+
bind(role: BindableRole, provider: string, model: string): Promise<void>;
|
|
296
|
+
/** Remove one role's binding. The role becomes unbound, never inherited. */
|
|
297
|
+
unbind(role: BindableRole): Promise<void>;
|
|
298
|
+
/** Run the exact bound route once; saving a credential never calls this. */
|
|
299
|
+
testRole(role: BindableRole): Promise<void>;
|
|
300
|
+
/** Cancel only the explicit provider probe; no Chat turn is involved. */
|
|
301
|
+
cancelProviderTest(): void;
|
|
302
|
+
/**
|
|
303
|
+
* Point the Harness's own default selection at what Chat is bound to.
|
|
304
|
+
*
|
|
305
|
+
* The link this subsystem was missing, and the failure it caused is worth
|
|
306
|
+
* stating plainly: a person added a provider, chose a model and assigned it
|
|
307
|
+
* to Chat, and still could not send. Every DeepWatch surface agreed the
|
|
308
|
+
* binding existed. It did — in DeepWatch's document. But the thing that
|
|
309
|
+
* actually routes a prompt is the Harness's model selection, which this
|
|
310
|
+
* distribution had *emptied* so that nothing would be chosen for anybody,
|
|
311
|
+
* and binding Chat never filled it in. Two records of one decision, and the
|
|
312
|
+
* one the runtime reads was the one nobody was writing.
|
|
313
|
+
*
|
|
314
|
+
* So a Chat binding writes both. `agent-default-model` is upstream's own
|
|
315
|
+
* settings section, read live by `AgentDefaultModelConfig` and re-read by a
|
|
316
|
+
* blank session on every look — so a session opened before the binding
|
|
317
|
+
* picks it up without being told.
|
|
318
|
+
*
|
|
319
|
+
* Only Chat. The other roles are DeepWatch's own concepts and have no
|
|
320
|
+
* upstream selection to keep in step; writing one for them would point the
|
|
321
|
+
* conversation at a model chosen for something else.
|
|
322
|
+
*/
|
|
323
|
+
private syncDefaultSelection;
|
|
324
|
+
private write;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Whether the capability a conversation needs can actually run.
|
|
328
|
+
*
|
|
329
|
+
* The one question the composer asks, given its own name so no surface has to
|
|
330
|
+
* remember which role Chat is or re-derive readiness to find out.
|
|
331
|
+
*/
|
|
332
|
+
export declare function chatReadiness(snapshot: BindingSnapshot): RoleReadiness | null;
|
|
333
|
+
export {};
|
|
334
|
+
//# sourceMappingURL=binding-state.d.ts.map
|