@yadsh/dsh-kv-persist 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 +110 -0
- package/compatibility.json +16 -0
- package/cordis.patch.yml +4 -0
- package/docs/dsh-kv-persist.md +3311 -0
- package/lib/backends/llama-cpp/backend.d.ts +20 -0
- package/lib/backends/llama-cpp/backend.d.ts.map +1 -0
- package/lib/backends/llama-cpp/backend.js +37 -0
- package/lib/backends/llama-cpp/backend.js.map +1 -0
- package/lib/backends/llama-cpp/client.d.ts +31 -0
- package/lib/backends/llama-cpp/client.d.ts.map +1 -0
- package/lib/backends/llama-cpp/client.js +120 -0
- package/lib/backends/llama-cpp/client.js.map +1 -0
- package/lib/backends/llama-cpp/discovery.d.ts +20 -0
- package/lib/backends/llama-cpp/discovery.d.ts.map +1 -0
- package/lib/backends/llama-cpp/discovery.js +33 -0
- package/lib/backends/llama-cpp/discovery.js.map +1 -0
- package/lib/backends/llama-cpp/types.d.ts +30 -0
- package/lib/backends/llama-cpp/types.d.ts.map +1 -0
- package/lib/backends/llama-cpp/types.js +9 -0
- package/lib/backends/llama-cpp/types.js.map +1 -0
- package/lib/backends/types.d.ts +52 -0
- package/lib/backends/types.d.ts.map +1 -0
- package/lib/backends/types.js +6 -0
- package/lib/backends/types.js.map +1 -0
- package/lib/config.d.ts +258 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +169 -0
- package/lib/config.js.map +1 -0
- package/lib/coordinator/checkpoint-policy.d.ts +19 -0
- package/lib/coordinator/checkpoint-policy.d.ts.map +1 -0
- package/lib/coordinator/checkpoint-policy.js +40 -0
- package/lib/coordinator/checkpoint-policy.js.map +1 -0
- package/lib/coordinator/circuit-breaker.d.ts +29 -0
- package/lib/coordinator/circuit-breaker.d.ts.map +1 -0
- package/lib/coordinator/circuit-breaker.js +62 -0
- package/lib/coordinator/circuit-breaker.js.map +1 -0
- package/lib/coordinator/coordinator.d.ts +74 -0
- package/lib/coordinator/coordinator.d.ts.map +1 -0
- package/lib/coordinator/coordinator.js +542 -0
- package/lib/coordinator/coordinator.js.map +1 -0
- package/lib/coordinator/slot-lease.d.ts +22 -0
- package/lib/coordinator/slot-lease.d.ts.map +1 -0
- package/lib/coordinator/slot-lease.js +38 -0
- package/lib/coordinator/slot-lease.js.map +1 -0
- package/lib/coordinator/state-machine.d.ts +65 -0
- package/lib/coordinator/state-machine.d.ts.map +1 -0
- package/lib/coordinator/state-machine.js +40 -0
- package/lib/coordinator/state-machine.js.map +1 -0
- package/lib/errors.d.ts +82 -0
- package/lib/errors.d.ts.map +1 -0
- package/lib/errors.js +113 -0
- package/lib/errors.js.map +1 -0
- package/lib/index.d.ts +26 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +17 -0
- package/lib/index.js.map +1 -0
- package/lib/logging/dsh-home.d.ts +13 -0
- package/lib/logging/dsh-home.d.ts.map +1 -0
- package/lib/logging/dsh-home.js +18 -0
- package/lib/logging/dsh-home.js.map +1 -0
- package/lib/logging/index.d.ts +10 -0
- package/lib/logging/index.d.ts.map +1 -0
- package/lib/logging/index.js +10 -0
- package/lib/logging/index.js.map +1 -0
- package/lib/logging/plugin-logger.d.ts +94 -0
- package/lib/logging/plugin-logger.d.ts.map +1 -0
- package/lib/logging/plugin-logger.js +397 -0
- package/lib/logging/plugin-logger.js.map +1 -0
- package/lib/observability/diagnostics.d.ts +37 -0
- package/lib/observability/diagnostics.d.ts.map +1 -0
- package/lib/observability/diagnostics.js +75 -0
- package/lib/observability/diagnostics.js.map +1 -0
- package/lib/observability/metrics.d.ts +38 -0
- package/lib/observability/metrics.d.ts.map +1 -0
- package/lib/observability/metrics.js +29 -0
- package/lib/observability/metrics.js.map +1 -0
- package/lib/service.d.ts +231 -0
- package/lib/service.d.ts.map +1 -0
- package/lib/service.js +232 -0
- package/lib/service.js.map +1 -0
- package/lib/snapshots/fingerprint.d.ts +53 -0
- package/lib/snapshots/fingerprint.d.ts.map +1 -0
- package/lib/snapshots/fingerprint.js +69 -0
- package/lib/snapshots/fingerprint.js.map +1 -0
- package/lib/snapshots/manifest.d.ts +51 -0
- package/lib/snapshots/manifest.d.ts.map +1 -0
- package/lib/snapshots/manifest.js +0 -0
- package/lib/snapshots/manifest.js.map +1 -0
- package/lib/snapshots/naming.d.ts +18 -0
- package/lib/snapshots/naming.d.ts.map +1 -0
- package/lib/snapshots/naming.js +33 -0
- package/lib/snapshots/naming.js.map +1 -0
- package/lib/snapshots/repository.d.ts +52 -0
- package/lib/snapshots/repository.d.ts.map +1 -0
- package/lib/snapshots/repository.js +270 -0
- package/lib/snapshots/repository.js.map +1 -0
- package/package.json +83 -0
package/lib/config.d.ts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration surface of the kv-persist plugin (SPEC §35-§37).
|
|
3
|
+
*
|
|
4
|
+
* The Schemastery schema in `index.ts` is the user-facing contract; this
|
|
5
|
+
* module resolves raw config into fully defaulted, validated values so the
|
|
6
|
+
* rest of the plugin never deals with optional fields.
|
|
7
|
+
*/
|
|
8
|
+
import z from "@deepseek-ai/schemastery";
|
|
9
|
+
/** Raw user-facing configuration (SPEC §36). */
|
|
10
|
+
export interface KvPersistConfig {
|
|
11
|
+
/** Master switch; when false the plugin passes every request through. */
|
|
12
|
+
readonly enabled?: boolean;
|
|
13
|
+
/** llama.cpp server connection. */
|
|
14
|
+
readonly backend?: {
|
|
15
|
+
readonly type?: "llama.cpp";
|
|
16
|
+
readonly baseURL?: string;
|
|
17
|
+
/** Management-API key; never logged. */
|
|
18
|
+
readonly apiKey?: string;
|
|
19
|
+
/** Bounded timeout for every persistence HTTP call (SPEC §59). */
|
|
20
|
+
readonly requestTimeoutMs?: number;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Explicit managed provider routes (SPEC §37). Requests to any other
|
|
24
|
+
* provider pass through untouched. Default: none (plugin inert).
|
|
25
|
+
*/
|
|
26
|
+
readonly providers?: readonly string[];
|
|
27
|
+
/** v0.1 supports single-slot only (SPEC §8). */
|
|
28
|
+
readonly mode?: "single-slot" | "managed-slots";
|
|
29
|
+
/** Physical slot used in single-slot mode. */
|
|
30
|
+
readonly slotId?: number;
|
|
31
|
+
/**
|
|
32
|
+
* Manual runtime identity escape hatch (SPEC §15): changing it makes all
|
|
33
|
+
* previously saved snapshots invisible without deleting them.
|
|
34
|
+
*/
|
|
35
|
+
readonly runtimeKey?: string;
|
|
36
|
+
/** Checkpoint policy (SPEC §26). */
|
|
37
|
+
readonly checkpoint?: {
|
|
38
|
+
/** Save a dirty slot before reassigning it. Default: true. */
|
|
39
|
+
readonly onSwitch?: boolean;
|
|
40
|
+
/** Final checkpoint during Cordis disposal. Default: true. */
|
|
41
|
+
readonly onShutdown?: boolean;
|
|
42
|
+
/** Checkpoint on the session/flush durability event. Default: true. */
|
|
43
|
+
readonly onSessionFlush?: boolean;
|
|
44
|
+
/** Save dirty state after this many idle milliseconds; 0 disables. Default: 30000. */
|
|
45
|
+
readonly idleMs?: number;
|
|
46
|
+
/** Checkpoint after every completed user turn. Default: false. */
|
|
47
|
+
readonly onTurnEnd?: boolean;
|
|
48
|
+
/** Reserved for future per-step checkpoints. Default: false. */
|
|
49
|
+
readonly onStepEnd?: boolean;
|
|
50
|
+
};
|
|
51
|
+
/** Restore behavior (SPEC §23-§24). */
|
|
52
|
+
readonly restore?: {
|
|
53
|
+
/** Restore compatible snapshots before a session's first request. Default: true. */
|
|
54
|
+
readonly enabled?: boolean;
|
|
55
|
+
/** Validate restored state (n_restored) after an HTTP 200. Default: true. */
|
|
56
|
+
readonly verify?: boolean;
|
|
57
|
+
};
|
|
58
|
+
/** Failure policy and circuit breaker (SPEC §32-§33). */
|
|
59
|
+
readonly failure?: {
|
|
60
|
+
/** Turn persistence failures into request failures. Default: false. */
|
|
61
|
+
readonly strict?: boolean;
|
|
62
|
+
/** Consecutive failures before the circuit opens. Default: 3. */
|
|
63
|
+
readonly maxConsecutiveFailures?: number;
|
|
64
|
+
/** Circuit open duration in milliseconds. Default: 60000. */
|
|
65
|
+
readonly cooldownMs?: number;
|
|
66
|
+
};
|
|
67
|
+
/** Local metadata storage (SPEC §39). */
|
|
68
|
+
readonly metadata?: {
|
|
69
|
+
/** Absolute metadata directory; blank uses `<$DSH_HOME>/cache/dsh-kv-persist`. */
|
|
70
|
+
readonly path?: string;
|
|
71
|
+
};
|
|
72
|
+
/** Structured logging verbosity. */
|
|
73
|
+
readonly logging?: {
|
|
74
|
+
/** `debug`, `info`, or `off`. Default: `info`. */
|
|
75
|
+
readonly level?: "debug" | "info" | "off";
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Fully resolved configuration. */
|
|
79
|
+
export interface ResolvedKvPersistConfig {
|
|
80
|
+
readonly enabled: boolean;
|
|
81
|
+
readonly backendType: "llama.cpp";
|
|
82
|
+
readonly baseURL: string;
|
|
83
|
+
readonly apiKey: string | null;
|
|
84
|
+
readonly requestTimeoutMs: number;
|
|
85
|
+
readonly providers: readonly string[];
|
|
86
|
+
readonly mode: "single-slot" | "managed-slots";
|
|
87
|
+
readonly slotId: number;
|
|
88
|
+
readonly runtimeKey: string | null;
|
|
89
|
+
readonly checkpoint: {
|
|
90
|
+
readonly onSwitch: boolean;
|
|
91
|
+
readonly onShutdown: boolean;
|
|
92
|
+
readonly onSessionFlush: boolean;
|
|
93
|
+
readonly idleMs: number;
|
|
94
|
+
readonly onTurnEnd: boolean;
|
|
95
|
+
readonly onStepEnd: boolean;
|
|
96
|
+
};
|
|
97
|
+
readonly restore: {
|
|
98
|
+
readonly enabled: boolean;
|
|
99
|
+
readonly verify: boolean;
|
|
100
|
+
};
|
|
101
|
+
readonly failure: {
|
|
102
|
+
readonly strict: boolean;
|
|
103
|
+
readonly maxConsecutiveFailures: number;
|
|
104
|
+
readonly cooldownMs: number;
|
|
105
|
+
};
|
|
106
|
+
readonly metadataPath: string | null;
|
|
107
|
+
readonly logLevel: "debug" | "info" | "off";
|
|
108
|
+
}
|
|
109
|
+
export declare const KV_PERSIST_DEFAULTS: {
|
|
110
|
+
readonly enabled: true;
|
|
111
|
+
readonly baseURL: "http://127.0.0.1:8080";
|
|
112
|
+
readonly requestTimeoutMs: 15000;
|
|
113
|
+
readonly mode: "single-slot";
|
|
114
|
+
readonly slotId: 0;
|
|
115
|
+
readonly onSwitch: true;
|
|
116
|
+
readonly onShutdown: true;
|
|
117
|
+
readonly onSessionFlush: true;
|
|
118
|
+
readonly idleMs: 30000;
|
|
119
|
+
readonly onTurnEnd: false;
|
|
120
|
+
readonly onStepEnd: false;
|
|
121
|
+
readonly restoreEnabled: true;
|
|
122
|
+
readonly restoreVerify: true;
|
|
123
|
+
readonly strict: false;
|
|
124
|
+
readonly maxConsecutiveFailures: 3;
|
|
125
|
+
readonly cooldownMs: 60000;
|
|
126
|
+
readonly logLevel: "info";
|
|
127
|
+
};
|
|
128
|
+
/**
|
|
129
|
+
* Resolve raw config into validated values. Throws `KV_INVARIANT` failures
|
|
130
|
+
* for structurally impossible config so misconfiguration is loud (SPEC §32
|
|
131
|
+
* only applies to runtime persistence failures, not to broken config).
|
|
132
|
+
*/
|
|
133
|
+
export declare function resolveKvPersistConfig(input?: KvPersistConfig): ResolvedKvPersistConfig;
|
|
134
|
+
/** True when the request route is explicitly managed (SPEC §37). */
|
|
135
|
+
export declare function isManagedProvider(config: ResolvedKvPersistConfig, provider: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Schemastery contract shown in DSH settings; every field is optional with a
|
|
138
|
+
* default so partial user config resolves. `resolveKvPersistConfig` remains
|
|
139
|
+
* the single source of truth for actual values (SPEC §36).
|
|
140
|
+
*/
|
|
141
|
+
export declare const KvPersistConfigSchema: z<Schemastery.ObjectS<{
|
|
142
|
+
enabled: z<boolean, boolean>;
|
|
143
|
+
backend: z<Schemastery.ObjectS<{
|
|
144
|
+
type: z<"llama.cpp", "llama.cpp">;
|
|
145
|
+
baseURL: z<string, string>;
|
|
146
|
+
apiKey: z<string, string>;
|
|
147
|
+
requestTimeoutMs: z<number, number>;
|
|
148
|
+
}>, Schemastery.ObjectT<{
|
|
149
|
+
type: z<"llama.cpp", "llama.cpp">;
|
|
150
|
+
baseURL: z<string, string>;
|
|
151
|
+
apiKey: z<string, string>;
|
|
152
|
+
requestTimeoutMs: z<number, number>;
|
|
153
|
+
}>>;
|
|
154
|
+
providers: z<string[], string[]>;
|
|
155
|
+
mode: z<"single-slot", "single-slot">;
|
|
156
|
+
slotId: z<number, number>;
|
|
157
|
+
runtimeKey: z<string, string>;
|
|
158
|
+
checkpoint: z<Schemastery.ObjectS<{
|
|
159
|
+
onSwitch: z<boolean, boolean>;
|
|
160
|
+
onShutdown: z<boolean, boolean>;
|
|
161
|
+
onSessionFlush: z<boolean, boolean>;
|
|
162
|
+
idleMs: z<number, number>;
|
|
163
|
+
onTurnEnd: z<boolean, boolean>;
|
|
164
|
+
onStepEnd: z<boolean, boolean>;
|
|
165
|
+
}>, Schemastery.ObjectT<{
|
|
166
|
+
onSwitch: z<boolean, boolean>;
|
|
167
|
+
onShutdown: z<boolean, boolean>;
|
|
168
|
+
onSessionFlush: z<boolean, boolean>;
|
|
169
|
+
idleMs: z<number, number>;
|
|
170
|
+
onTurnEnd: z<boolean, boolean>;
|
|
171
|
+
onStepEnd: z<boolean, boolean>;
|
|
172
|
+
}>>;
|
|
173
|
+
restore: z<Schemastery.ObjectS<{
|
|
174
|
+
enabled: z<boolean, boolean>;
|
|
175
|
+
verify: z<boolean, boolean>;
|
|
176
|
+
}>, Schemastery.ObjectT<{
|
|
177
|
+
enabled: z<boolean, boolean>;
|
|
178
|
+
verify: z<boolean, boolean>;
|
|
179
|
+
}>>;
|
|
180
|
+
failure: z<Schemastery.ObjectS<{
|
|
181
|
+
strict: z<boolean, boolean>;
|
|
182
|
+
maxConsecutiveFailures: z<number, number>;
|
|
183
|
+
cooldownMs: z<number, number>;
|
|
184
|
+
}>, Schemastery.ObjectT<{
|
|
185
|
+
strict: z<boolean, boolean>;
|
|
186
|
+
maxConsecutiveFailures: z<number, number>;
|
|
187
|
+
cooldownMs: z<number, number>;
|
|
188
|
+
}>>;
|
|
189
|
+
metadata: z<Schemastery.ObjectS<{
|
|
190
|
+
path: z<string, string>;
|
|
191
|
+
}>, Schemastery.ObjectT<{
|
|
192
|
+
path: z<string, string>;
|
|
193
|
+
}>>;
|
|
194
|
+
logging: z<Schemastery.ObjectS<{
|
|
195
|
+
level: z<"debug" | "info" | "off", "debug" | "info" | "off">;
|
|
196
|
+
}>, Schemastery.ObjectT<{
|
|
197
|
+
level: z<"debug" | "info" | "off", "debug" | "info" | "off">;
|
|
198
|
+
}>>;
|
|
199
|
+
}>, Schemastery.ObjectT<{
|
|
200
|
+
enabled: z<boolean, boolean>;
|
|
201
|
+
backend: z<Schemastery.ObjectS<{
|
|
202
|
+
type: z<"llama.cpp", "llama.cpp">;
|
|
203
|
+
baseURL: z<string, string>;
|
|
204
|
+
apiKey: z<string, string>;
|
|
205
|
+
requestTimeoutMs: z<number, number>;
|
|
206
|
+
}>, Schemastery.ObjectT<{
|
|
207
|
+
type: z<"llama.cpp", "llama.cpp">;
|
|
208
|
+
baseURL: z<string, string>;
|
|
209
|
+
apiKey: z<string, string>;
|
|
210
|
+
requestTimeoutMs: z<number, number>;
|
|
211
|
+
}>>;
|
|
212
|
+
providers: z<string[], string[]>;
|
|
213
|
+
mode: z<"single-slot", "single-slot">;
|
|
214
|
+
slotId: z<number, number>;
|
|
215
|
+
runtimeKey: z<string, string>;
|
|
216
|
+
checkpoint: z<Schemastery.ObjectS<{
|
|
217
|
+
onSwitch: z<boolean, boolean>;
|
|
218
|
+
onShutdown: z<boolean, boolean>;
|
|
219
|
+
onSessionFlush: z<boolean, boolean>;
|
|
220
|
+
idleMs: z<number, number>;
|
|
221
|
+
onTurnEnd: z<boolean, boolean>;
|
|
222
|
+
onStepEnd: z<boolean, boolean>;
|
|
223
|
+
}>, Schemastery.ObjectT<{
|
|
224
|
+
onSwitch: z<boolean, boolean>;
|
|
225
|
+
onShutdown: z<boolean, boolean>;
|
|
226
|
+
onSessionFlush: z<boolean, boolean>;
|
|
227
|
+
idleMs: z<number, number>;
|
|
228
|
+
onTurnEnd: z<boolean, boolean>;
|
|
229
|
+
onStepEnd: z<boolean, boolean>;
|
|
230
|
+
}>>;
|
|
231
|
+
restore: z<Schemastery.ObjectS<{
|
|
232
|
+
enabled: z<boolean, boolean>;
|
|
233
|
+
verify: z<boolean, boolean>;
|
|
234
|
+
}>, Schemastery.ObjectT<{
|
|
235
|
+
enabled: z<boolean, boolean>;
|
|
236
|
+
verify: z<boolean, boolean>;
|
|
237
|
+
}>>;
|
|
238
|
+
failure: z<Schemastery.ObjectS<{
|
|
239
|
+
strict: z<boolean, boolean>;
|
|
240
|
+
maxConsecutiveFailures: z<number, number>;
|
|
241
|
+
cooldownMs: z<number, number>;
|
|
242
|
+
}>, Schemastery.ObjectT<{
|
|
243
|
+
strict: z<boolean, boolean>;
|
|
244
|
+
maxConsecutiveFailures: z<number, number>;
|
|
245
|
+
cooldownMs: z<number, number>;
|
|
246
|
+
}>>;
|
|
247
|
+
metadata: z<Schemastery.ObjectS<{
|
|
248
|
+
path: z<string, string>;
|
|
249
|
+
}>, Schemastery.ObjectT<{
|
|
250
|
+
path: z<string, string>;
|
|
251
|
+
}>>;
|
|
252
|
+
logging: z<Schemastery.ObjectS<{
|
|
253
|
+
level: z<"debug" | "info" | "off", "debug" | "info" | "off">;
|
|
254
|
+
}>, Schemastery.ObjectT<{
|
|
255
|
+
level: z<"debug" | "info" | "off", "debug" | "info" | "off">;
|
|
256
|
+
}>>;
|
|
257
|
+
}>>;
|
|
258
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration surface of the kv-persist plugin (SPEC §35-§37).
|
|
3
|
+
*
|
|
4
|
+
* The Schemastery schema in `index.ts` is the user-facing contract; this
|
|
5
|
+
* module resolves raw config into fully defaulted, validated values so the
|
|
6
|
+
* rest of the plugin never deals with optional fields.
|
|
7
|
+
*/
|
|
8
|
+
import z from "@deepseek-ai/schemastery";
|
|
9
|
+
import { KvPersistError } from "./errors.js";
|
|
10
|
+
export const KV_PERSIST_DEFAULTS = {
|
|
11
|
+
enabled: true,
|
|
12
|
+
baseURL: "http://127.0.0.1:8080",
|
|
13
|
+
requestTimeoutMs: 15_000,
|
|
14
|
+
mode: "single-slot",
|
|
15
|
+
slotId: 0,
|
|
16
|
+
onSwitch: true,
|
|
17
|
+
onShutdown: true,
|
|
18
|
+
onSessionFlush: true,
|
|
19
|
+
idleMs: 30_000,
|
|
20
|
+
onTurnEnd: false,
|
|
21
|
+
onStepEnd: false,
|
|
22
|
+
restoreEnabled: true,
|
|
23
|
+
restoreVerify: true,
|
|
24
|
+
strict: false,
|
|
25
|
+
maxConsecutiveFailures: 3,
|
|
26
|
+
cooldownMs: 60_000,
|
|
27
|
+
logLevel: "info",
|
|
28
|
+
};
|
|
29
|
+
function requireInt(name, value, fallback, minimum) {
|
|
30
|
+
if (value === undefined)
|
|
31
|
+
return fallback;
|
|
32
|
+
if (!Number.isInteger(value) || value < minimum) {
|
|
33
|
+
throw new KvPersistError("KV_INVARIANT", `config "${name}" must be an integer >= ${minimum}`);
|
|
34
|
+
}
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
function requirePositiveMs(name, value, fallback) {
|
|
38
|
+
return requireInt(name, value, fallback, 1);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve raw config into validated values. Throws `KV_INVARIANT` failures
|
|
42
|
+
* for structurally impossible config so misconfiguration is loud (SPEC §32
|
|
43
|
+
* only applies to runtime persistence failures, not to broken config).
|
|
44
|
+
*/
|
|
45
|
+
export function resolveKvPersistConfig(input = {}) {
|
|
46
|
+
if (input.backend?.type !== undefined && input.backend.type !== "llama.cpp") {
|
|
47
|
+
throw new KvPersistError("KV_BACKEND_UNSUPPORTED", `backend type "${String(input.backend.type)}" is not supported in v0.1 (SPEC §12)`);
|
|
48
|
+
}
|
|
49
|
+
if (input.mode !== undefined && input.mode !== "single-slot" && input.mode !== "managed-slots") {
|
|
50
|
+
throw new KvPersistError("KV_INVARIANT", `unknown mode "${String(input.mode)}"`);
|
|
51
|
+
}
|
|
52
|
+
if (input.mode === "managed-slots") {
|
|
53
|
+
throw new KvPersistError("KV_BACKEND_UNSUPPORTED", 'mode "managed-slots" is planned for v0.3 (SPEC §63); v0.1 supports only "single-slot"');
|
|
54
|
+
}
|
|
55
|
+
const logLevel = input.logging?.level ?? KV_PERSIST_DEFAULTS.logLevel;
|
|
56
|
+
if (logLevel !== "debug" && logLevel !== "info" && logLevel !== "off") {
|
|
57
|
+
throw new KvPersistError("KV_INVARIANT", `unknown logging.level "${String(logLevel)}"`);
|
|
58
|
+
}
|
|
59
|
+
const baseURL = (input.backend?.baseURL ?? KV_PERSIST_DEFAULTS.baseURL).trim();
|
|
60
|
+
if (baseURL.length === 0) {
|
|
61
|
+
throw new KvPersistError("KV_INVARIANT", "backend.baseURL must not be blank");
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
enabled: input.enabled ?? KV_PERSIST_DEFAULTS.enabled,
|
|
65
|
+
backendType: input.backend?.type ?? "llama.cpp",
|
|
66
|
+
baseURL: baseURL.replace(/\/+$/, ""),
|
|
67
|
+
apiKey: input.backend?.apiKey && input.backend.apiKey.length > 0 ? input.backend.apiKey : null,
|
|
68
|
+
requestTimeoutMs: requirePositiveMs("backend.requestTimeoutMs", input.backend?.requestTimeoutMs, KV_PERSIST_DEFAULTS.requestTimeoutMs),
|
|
69
|
+
providers: (input.providers ?? []).filter((p) => p.length > 0),
|
|
70
|
+
mode: input.mode ?? KV_PERSIST_DEFAULTS.mode,
|
|
71
|
+
slotId: requireInt("slotId", input.slotId, KV_PERSIST_DEFAULTS.slotId, 0),
|
|
72
|
+
runtimeKey: input.runtimeKey && input.runtimeKey.length > 0 ? input.runtimeKey : null,
|
|
73
|
+
checkpoint: {
|
|
74
|
+
onSwitch: input.checkpoint?.onSwitch ?? KV_PERSIST_DEFAULTS.onSwitch,
|
|
75
|
+
onShutdown: input.checkpoint?.onShutdown ?? KV_PERSIST_DEFAULTS.onShutdown,
|
|
76
|
+
onSessionFlush: input.checkpoint?.onSessionFlush ?? KV_PERSIST_DEFAULTS.onSessionFlush,
|
|
77
|
+
idleMs: requireInt("checkpoint.idleMs", input.checkpoint?.idleMs, KV_PERSIST_DEFAULTS.idleMs, 0),
|
|
78
|
+
onTurnEnd: input.checkpoint?.onTurnEnd ?? KV_PERSIST_DEFAULTS.onTurnEnd,
|
|
79
|
+
onStepEnd: input.checkpoint?.onStepEnd ?? KV_PERSIST_DEFAULTS.onStepEnd,
|
|
80
|
+
},
|
|
81
|
+
restore: {
|
|
82
|
+
enabled: input.restore?.enabled ?? KV_PERSIST_DEFAULTS.restoreEnabled,
|
|
83
|
+
verify: input.restore?.verify ?? KV_PERSIST_DEFAULTS.restoreVerify,
|
|
84
|
+
},
|
|
85
|
+
failure: {
|
|
86
|
+
strict: input.failure?.strict ?? KV_PERSIST_DEFAULTS.strict,
|
|
87
|
+
maxConsecutiveFailures: requireInt("failure.maxConsecutiveFailures", input.failure?.maxConsecutiveFailures, KV_PERSIST_DEFAULTS.maxConsecutiveFailures, 1),
|
|
88
|
+
cooldownMs: requireInt("failure.cooldownMs", input.failure?.cooldownMs, KV_PERSIST_DEFAULTS.cooldownMs, 1),
|
|
89
|
+
},
|
|
90
|
+
metadataPath: input.metadata?.path && input.metadata.path.trim().length > 0
|
|
91
|
+
? input.metadata.path.trim()
|
|
92
|
+
: null,
|
|
93
|
+
logLevel,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** True when the request route is explicitly managed (SPEC §37). */
|
|
97
|
+
export function isManagedProvider(config, provider) {
|
|
98
|
+
return config.providers.includes(provider);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Schemastery contract shown in DSH settings; every field is optional with a
|
|
102
|
+
* default so partial user config resolves. `resolveKvPersistConfig` remains
|
|
103
|
+
* the single source of truth for actual values (SPEC §36).
|
|
104
|
+
*/
|
|
105
|
+
export const KvPersistConfigSchema = z.object({
|
|
106
|
+
enabled: z.boolean().default(true),
|
|
107
|
+
backend: z
|
|
108
|
+
.object({
|
|
109
|
+
type: z.const("llama.cpp").default("llama.cpp"),
|
|
110
|
+
baseURL: z.string().default(KV_PERSIST_DEFAULTS.baseURL),
|
|
111
|
+
apiKey: z.string().default(""),
|
|
112
|
+
requestTimeoutMs: z.number().default(KV_PERSIST_DEFAULTS.requestTimeoutMs),
|
|
113
|
+
})
|
|
114
|
+
.default({
|
|
115
|
+
type: "llama.cpp",
|
|
116
|
+
baseURL: KV_PERSIST_DEFAULTS.baseURL,
|
|
117
|
+
apiKey: "",
|
|
118
|
+
requestTimeoutMs: KV_PERSIST_DEFAULTS.requestTimeoutMs,
|
|
119
|
+
}),
|
|
120
|
+
providers: z.array(z.string()).default([]),
|
|
121
|
+
mode: z.const("single-slot").default("single-slot"),
|
|
122
|
+
slotId: z.number().default(KV_PERSIST_DEFAULTS.slotId),
|
|
123
|
+
runtimeKey: z.string().default(""),
|
|
124
|
+
checkpoint: z
|
|
125
|
+
.object({
|
|
126
|
+
onSwitch: z.boolean().default(KV_PERSIST_DEFAULTS.onSwitch),
|
|
127
|
+
onShutdown: z.boolean().default(KV_PERSIST_DEFAULTS.onShutdown),
|
|
128
|
+
onSessionFlush: z.boolean().default(KV_PERSIST_DEFAULTS.onSessionFlush),
|
|
129
|
+
idleMs: z.number().default(KV_PERSIST_DEFAULTS.idleMs),
|
|
130
|
+
onTurnEnd: z.boolean().default(KV_PERSIST_DEFAULTS.onTurnEnd),
|
|
131
|
+
onStepEnd: z.boolean().default(KV_PERSIST_DEFAULTS.onStepEnd),
|
|
132
|
+
})
|
|
133
|
+
.default({
|
|
134
|
+
onSwitch: KV_PERSIST_DEFAULTS.onSwitch,
|
|
135
|
+
onShutdown: KV_PERSIST_DEFAULTS.onShutdown,
|
|
136
|
+
onSessionFlush: KV_PERSIST_DEFAULTS.onSessionFlush,
|
|
137
|
+
idleMs: KV_PERSIST_DEFAULTS.idleMs,
|
|
138
|
+
onTurnEnd: KV_PERSIST_DEFAULTS.onTurnEnd,
|
|
139
|
+
onStepEnd: KV_PERSIST_DEFAULTS.onStepEnd,
|
|
140
|
+
}),
|
|
141
|
+
restore: z
|
|
142
|
+
.object({
|
|
143
|
+
enabled: z.boolean().default(KV_PERSIST_DEFAULTS.restoreEnabled),
|
|
144
|
+
verify: z.boolean().default(KV_PERSIST_DEFAULTS.restoreVerify),
|
|
145
|
+
})
|
|
146
|
+
.default({ enabled: KV_PERSIST_DEFAULTS.restoreEnabled, verify: KV_PERSIST_DEFAULTS.restoreVerify }),
|
|
147
|
+
failure: z
|
|
148
|
+
.object({
|
|
149
|
+
strict: z.boolean().default(KV_PERSIST_DEFAULTS.strict),
|
|
150
|
+
maxConsecutiveFailures: z.number().default(KV_PERSIST_DEFAULTS.maxConsecutiveFailures),
|
|
151
|
+
cooldownMs: z.number().default(KV_PERSIST_DEFAULTS.cooldownMs),
|
|
152
|
+
})
|
|
153
|
+
.default({
|
|
154
|
+
strict: KV_PERSIST_DEFAULTS.strict,
|
|
155
|
+
maxConsecutiveFailures: KV_PERSIST_DEFAULTS.maxConsecutiveFailures,
|
|
156
|
+
cooldownMs: KV_PERSIST_DEFAULTS.cooldownMs,
|
|
157
|
+
}),
|
|
158
|
+
metadata: z
|
|
159
|
+
.object({
|
|
160
|
+
path: z.string().default(""),
|
|
161
|
+
})
|
|
162
|
+
.default({ path: "" }),
|
|
163
|
+
logging: z
|
|
164
|
+
.object({
|
|
165
|
+
level: z.union([z.const("debug"), z.const("info"), z.const("off")]).default("info"),
|
|
166
|
+
})
|
|
167
|
+
.default({ level: "info" }),
|
|
168
|
+
});
|
|
169
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint policy (SPEC §26, §52).
|
|
3
|
+
*
|
|
4
|
+
* Answers "should we checkpoint now?" for every trigger the v0.1 plugin
|
|
5
|
+
* wires: slot switch, session flush, session disposal, turn end, idle
|
|
6
|
+
* timer, and shutdown. The default recommendation is switch + idle +
|
|
7
|
+
* shutdown (+ flush), per SPEC §26.
|
|
8
|
+
*/
|
|
9
|
+
import type { ResolvedKvPersistConfig } from "../config.js";
|
|
10
|
+
import type { SessionRuntime } from "./state-machine.js";
|
|
11
|
+
export type CheckpointTrigger = "switch" | "idle" | "session-flush" | "session-disposed" | "turn-end" | "shutdown" | "manual";
|
|
12
|
+
/** Pure decision helper over config + runtime state. */
|
|
13
|
+
export declare class CheckpointPolicy {
|
|
14
|
+
#private;
|
|
15
|
+
constructor(config: ResolvedKvPersistConfig);
|
|
16
|
+
/** True when the trigger is enabled and the session actually needs a save. */
|
|
17
|
+
shouldCheckpoint(runtime: SessionRuntime | undefined, trigger: CheckpointTrigger): boolean;
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=checkpoint-policy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-policy.d.ts","sourceRoot":"","sources":["../../src/coordinator/checkpoint-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AAE5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,MAAM,iBAAiB,GACzB,QAAQ,GACR,MAAM,GACN,eAAe,GACf,kBAAkB,GAClB,UAAU,GACV,UAAU,GACV,QAAQ,CAAC;AAEb,wDAAwD;AACxD,qBAAa,gBAAgB;;gBAGf,MAAM,EAAE,uBAAuB;IAI3C,8EAA8E;IAC9E,gBAAgB,CAAC,OAAO,EAAE,cAAc,GAAG,SAAS,EAAE,OAAO,EAAE,iBAAiB,GAAG,OAAO;CAoB3F"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkpoint policy (SPEC §26, §52).
|
|
3
|
+
*
|
|
4
|
+
* Answers "should we checkpoint now?" for every trigger the v0.1 plugin
|
|
5
|
+
* wires: slot switch, session flush, session disposal, turn end, idle
|
|
6
|
+
* timer, and shutdown. The default recommendation is switch + idle +
|
|
7
|
+
* shutdown (+ flush), per SPEC §26.
|
|
8
|
+
*/
|
|
9
|
+
import { isDirty } from "./state-machine.js";
|
|
10
|
+
/** Pure decision helper over config + runtime state. */
|
|
11
|
+
export class CheckpointPolicy {
|
|
12
|
+
#config;
|
|
13
|
+
constructor(config) {
|
|
14
|
+
this.#config = config;
|
|
15
|
+
}
|
|
16
|
+
/** True when the trigger is enabled and the session actually needs a save. */
|
|
17
|
+
shouldCheckpoint(runtime, trigger) {
|
|
18
|
+
if (runtime === undefined)
|
|
19
|
+
return false;
|
|
20
|
+
if (!isDirty(runtime))
|
|
21
|
+
return false;
|
|
22
|
+
switch (trigger) {
|
|
23
|
+
case "switch":
|
|
24
|
+
return this.#config.checkpoint.onSwitch;
|
|
25
|
+
case "idle":
|
|
26
|
+
return this.#config.checkpoint.idleMs > 0;
|
|
27
|
+
case "session-flush":
|
|
28
|
+
return this.#config.checkpoint.onSessionFlush;
|
|
29
|
+
case "session-disposed":
|
|
30
|
+
return this.#config.checkpoint.onSwitch || this.#config.checkpoint.onShutdown;
|
|
31
|
+
case "turn-end":
|
|
32
|
+
return this.#config.checkpoint.onTurnEnd;
|
|
33
|
+
case "shutdown":
|
|
34
|
+
return this.#config.checkpoint.onShutdown;
|
|
35
|
+
case "manual":
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=checkpoint-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkpoint-policy.js","sourceRoot":"","sources":["../../src/coordinator/checkpoint-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAY7C,wDAAwD;AACxD,MAAM,OAAO,gBAAgB;IAClB,OAAO,CAA0B;IAE1C,YAAY,MAA+B;QACzC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,8EAA8E;IAC9E,gBAAgB,CAAC,OAAmC,EAAE,OAA0B;QAC9E,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,KAAK,CAAC;QACxC,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAAE,OAAO,KAAK,CAAC;QACpC,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC;YAC1C,KAAK,MAAM;gBACT,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,CAAC;YAC5C,KAAK,eAAe;gBAClB,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC;YAChD,KAAK,kBAAkB;gBACrB,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,QAAQ,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;YAChF,KAAK,UAAU;gBACb,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC;YAC3C,KAAK,UAAU;gBACb,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,UAAU,CAAC;YAC5C,KAAK,QAAQ;gBACX,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence circuit breaker (SPEC §33).
|
|
3
|
+
*
|
|
4
|
+
* When llama slot persistence is broken, retrying it on every request would
|
|
5
|
+
* waste seconds each time. After N consecutive persistence failures the
|
|
6
|
+
* breaker opens for a cooldown; while open, requests pass straight through
|
|
7
|
+
* to ordinary inference (which stays active). After the cooldown one probe
|
|
8
|
+
* attempt is allowed (half-open).
|
|
9
|
+
*/
|
|
10
|
+
export type CircuitState = "healthy" | "degraded" | "open" | "half-open";
|
|
11
|
+
export interface CircuitBreakerOptions {
|
|
12
|
+
readonly maxConsecutiveFailures: number;
|
|
13
|
+
readonly cooldownMs: number;
|
|
14
|
+
}
|
|
15
|
+
export declare class CircuitBreaker {
|
|
16
|
+
#private;
|
|
17
|
+
constructor(options: CircuitBreakerOptions);
|
|
18
|
+
get state(): CircuitState;
|
|
19
|
+
get consecutiveFailures(): number;
|
|
20
|
+
/** True when a persistence operation may be attempted at `now`. */
|
|
21
|
+
allows(now: number): boolean;
|
|
22
|
+
/** Whether persistence is currently skipped entirely (open without probe). */
|
|
23
|
+
isOpen(now: number): boolean;
|
|
24
|
+
recordSuccess(): void;
|
|
25
|
+
recordFailure(now: number): void;
|
|
26
|
+
/** Manual recovery hook (e.g. a successful probe). */
|
|
27
|
+
reset(): void;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=circuit-breaker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.d.ts","sourceRoot":"","sources":["../../src/coordinator/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,YAAY,GAAG,SAAS,GAAG,UAAU,GAAG,MAAM,GAAG,WAAW,CAAC;AAEzE,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,sBAAsB,EAAE,MAAM,CAAC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,qBAAa,cAAc;;gBAOb,OAAO,EAAE,qBAAqB;IAK1C,IAAI,KAAK,IAAI,YAAY,CAExB;IAED,IAAI,mBAAmB,IAAI,MAAM,CAEhC;IAED,mEAAmE;IACnE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAS5B,8EAA8E;IAC9E,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B,aAAa,IAAI,IAAI;IAKrB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAUhC,sDAAsD;IACtD,KAAK,IAAI,IAAI;CAKd"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Persistence circuit breaker (SPEC §33).
|
|
3
|
+
*
|
|
4
|
+
* When llama slot persistence is broken, retrying it on every request would
|
|
5
|
+
* waste seconds each time. After N consecutive persistence failures the
|
|
6
|
+
* breaker opens for a cooldown; while open, requests pass straight through
|
|
7
|
+
* to ordinary inference (which stays active). After the cooldown one probe
|
|
8
|
+
* attempt is allowed (half-open).
|
|
9
|
+
*/
|
|
10
|
+
export class CircuitBreaker {
|
|
11
|
+
#maxConsecutiveFailures;
|
|
12
|
+
#cooldownMs;
|
|
13
|
+
#consecutiveFailures = 0;
|
|
14
|
+
#openUntil = 0;
|
|
15
|
+
#state = "healthy";
|
|
16
|
+
constructor(options) {
|
|
17
|
+
this.#maxConsecutiveFailures = options.maxConsecutiveFailures;
|
|
18
|
+
this.#cooldownMs = options.cooldownMs;
|
|
19
|
+
}
|
|
20
|
+
get state() {
|
|
21
|
+
return this.#state;
|
|
22
|
+
}
|
|
23
|
+
get consecutiveFailures() {
|
|
24
|
+
return this.#consecutiveFailures;
|
|
25
|
+
}
|
|
26
|
+
/** True when a persistence operation may be attempted at `now`. */
|
|
27
|
+
allows(now) {
|
|
28
|
+
if (this.#state === "open") {
|
|
29
|
+
if (now < this.#openUntil)
|
|
30
|
+
return false;
|
|
31
|
+
this.#state = "half-open";
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
/** Whether persistence is currently skipped entirely (open without probe). */
|
|
37
|
+
isOpen(now) {
|
|
38
|
+
return this.#state === "open" && now < this.#openUntil;
|
|
39
|
+
}
|
|
40
|
+
recordSuccess() {
|
|
41
|
+
this.#consecutiveFailures = 0;
|
|
42
|
+
if (this.#state !== "healthy")
|
|
43
|
+
this.#state = "healthy";
|
|
44
|
+
}
|
|
45
|
+
recordFailure(now) {
|
|
46
|
+
this.#consecutiveFailures += 1;
|
|
47
|
+
if (this.#consecutiveFailures >= this.#maxConsecutiveFailures) {
|
|
48
|
+
this.#state = "open";
|
|
49
|
+
this.#openUntil = now + this.#cooldownMs;
|
|
50
|
+
}
|
|
51
|
+
else if (this.#state === "healthy") {
|
|
52
|
+
this.#state = "degraded";
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/** Manual recovery hook (e.g. a successful probe). */
|
|
56
|
+
reset() {
|
|
57
|
+
this.#consecutiveFailures = 0;
|
|
58
|
+
this.#openUntil = 0;
|
|
59
|
+
this.#state = "healthy";
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=circuit-breaker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"circuit-breaker.js","sourceRoot":"","sources":["../../src/coordinator/circuit-breaker.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AASH,MAAM,OAAO,cAAc;IAChB,uBAAuB,CAAS;IAChC,WAAW,CAAS;IAC7B,oBAAoB,GAAG,CAAC,CAAC;IACzB,UAAU,GAAG,CAAC,CAAC;IACf,MAAM,GAAiB,SAAS,CAAC;IAEjC,YAAY,OAA8B;QACxC,IAAI,CAAC,uBAAuB,GAAG,OAAO,CAAC,sBAAsB,CAAC;QAC9D,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IACxC,CAAC;IAED,IAAI,KAAK;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACnC,CAAC;IAED,mEAAmE;IACnE,MAAM,CAAC,GAAW;QAChB,IAAI,IAAI,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;YAC3B,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU;gBAAE,OAAO,KAAK,CAAC;YACxC,IAAI,CAAC,MAAM,GAAG,WAAW,CAAC;YAC1B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,8EAA8E;IAC9E,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,MAAM,KAAK,MAAM,IAAI,GAAG,GAAG,IAAI,CAAC,UAAU,CAAC;IACzD,CAAC;IAED,aAAa;QACX,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAC9B,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;YAAE,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IACzD,CAAC;IAED,aAAa,CAAC,GAAW;QACvB,IAAI,CAAC,oBAAoB,IAAI,CAAC,CAAC;QAC/B,IAAI,IAAI,CAAC,oBAAoB,IAAI,IAAI,CAAC,uBAAuB,EAAE,CAAC;YAC9D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,CAAC,UAAU,GAAG,GAAG,GAAG,IAAI,CAAC,WAAW,CAAC;QAC3C,CAAC;aAAM,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACrC,IAAI,CAAC,MAAM,GAAG,UAAU,CAAC;QAC3B,CAAC;IACH,CAAC;IAED,sDAAsD;IACtD,KAAK;QACH,IAAI,CAAC,oBAAoB,GAAG,CAAC,CAAC;QAC9B,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,MAAM,GAAG,SAAS,CAAC;IAC1B,CAAC;CACF"}
|