@camstack/system 1.2.90 → 1.2.92
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/dist/addon-runner.js +1 -1
- package/dist/addon-runner.mjs +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.js +1 -1
- package/dist/builtins/addon-pages-aggregator/addon-pages-aggregator.addon.mjs +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.js +1 -1
- package/dist/builtins/addon-widgets-aggregator/addon-widgets-aggregator.addon.mjs +1 -1
- package/dist/builtins/alerts/alerts.addon.js +1 -1
- package/dist/builtins/alerts/alerts.addon.mjs +1 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.js +25 -1
- package/dist/builtins/backup-orchestrator/backup-orchestrator.addon.mjs +25 -1
- package/dist/builtins/console-logging/index.js +1 -1
- package/dist/builtins/console-logging/index.mjs +1 -1
- package/dist/builtins/core-blocks/blocks-integration.d.ts +34 -1
- package/dist/builtins/core-blocks/core-block-store.d.ts +11 -0
- package/dist/builtins/core-blocks/core-blocks.addon.js +80 -22
- package/dist/builtins/core-blocks/core-blocks.addon.mjs +80 -22
- package/dist/builtins/device-manager/device-manager.addon.js +1 -1
- package/dist/builtins/device-manager/device-manager.addon.mjs +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.js +1 -1
- package/dist/builtins/doorbell/virtual-doorbell.addon.mjs +1 -1
- package/dist/builtins/hub-forwarder/index.js +1 -1
- package/dist/builtins/hub-forwarder/index.mjs +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.js +1 -1
- package/dist/builtins/liveness-monitor/liveness-monitor.addon.mjs +1 -1
- package/dist/builtins/local-auth/auth-schema.d.ts +42 -0
- package/dist/builtins/local-auth/local-auth.addon.js +43 -1
- package/dist/builtins/local-auth/local-auth.addon.mjs +43 -1
- package/dist/builtins/local-network/local-network.addon.js +1 -1
- package/dist/builtins/local-network/local-network.addon.mjs +1 -1
- package/dist/builtins/loki-logging/index.js +1 -1
- package/dist/builtins/loki-logging/index.mjs +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.js +1 -1
- package/dist/builtins/native-metrics/native-metrics.addon.mjs +1 -1
- package/dist/builtins/platform-probe/index.js +1 -1
- package/dist/builtins/platform-probe/index.mjs +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.js +1 -1
- package/dist/builtins/remote-access-orchestrator/remote-access-orchestrator.addon.mjs +1 -1
- package/dist/builtins/snapshot/index.js +1 -1
- package/dist/builtins/snapshot/index.mjs +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.js +1 -1
- package/dist/builtins/sqlite-storage/filesystem-storage.addon.mjs +1 -1
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.js +16 -5
- package/dist/builtins/sqlite-storage/sqlite-settings.addon.mjs +16 -5
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.js +19 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.addon.mjs +19 -2
- package/dist/builtins/storage-orchestrator/storage-orchestrator.service.d.ts +12 -0
- package/dist/builtins/system-config/system-config.addon.js +1 -1
- package/dist/builtins/system-config/system-config.addon.mjs +1 -1
- package/dist/builtins/winston-logging/index.js +1 -1
- package/dist/builtins/winston-logging/index.mjs +1 -1
- package/dist/{dist-CYqL8oZq.js → dist-BH2tZ9ZN.js} +525 -47
- package/dist/{dist-DMhxx5Kr.mjs → dist-DXDvrBi0.mjs} +525 -47
- package/dist/index.js +78 -6
- package/dist/index.mjs +78 -6
- package/dist/kernel/addon-health-monitor.d.ts +10 -1
- package/dist/logging/log-manager.d.ts +28 -0
- package/dist/{manifest-python-deps-C0zkl1Ae.js → manifest-python-deps-BZO_eMn-.js} +1 -7
- package/dist/{manifest-python-deps-fWzdEasI.mjs → manifest-python-deps-D3hP9W8D.mjs} +2 -8
- package/package.json +1 -1
|
@@ -728,12 +728,6 @@ var WELL_KNOWN_TAB_MAP = Object.fromEntries([
|
|
|
728
728
|
icon: "shapes",
|
|
729
729
|
order: 38
|
|
730
730
|
},
|
|
731
|
-
{
|
|
732
|
-
id: "scenes",
|
|
733
|
-
label: "Scenes",
|
|
734
|
-
icon: "scan-eye",
|
|
735
|
-
order: 36
|
|
736
|
-
},
|
|
737
731
|
{
|
|
738
732
|
id: "analytics",
|
|
739
733
|
label: "Analytics",
|
|
@@ -10105,6 +10099,17 @@ var LlmImageSchema = z.object({
|
|
|
10105
10099
|
bytes: z.instanceof(Uint8Array),
|
|
10106
10100
|
mimeType: z.string()
|
|
10107
10101
|
});
|
|
10102
|
+
/**
|
|
10103
|
+
* Retry policy. `enabled: false` is NOT the same as `maxAttempts: 1` in intent —
|
|
10104
|
+
* the flag is what a consumer table flips, the count is what the operator tunes.
|
|
10105
|
+
* A retry doubles the wall time of a call, so the two gates that run inside a
|
|
10106
|
+
* notification's budget keep it off (see `CONSUMER_RETRY_POLICY` in addon-ai).
|
|
10107
|
+
*/
|
|
10108
|
+
var LlmRetryPolicySchema = z.object({
|
|
10109
|
+
enabled: z.boolean().default(false),
|
|
10110
|
+
/** Total attempts INCLUDING the first. 1 = no retry. */
|
|
10111
|
+
maxAttempts: z.number().int().min(1).max(5).default(1)
|
|
10112
|
+
});
|
|
10108
10113
|
var LlmGenerateBaseInputSchema = z.object({
|
|
10109
10114
|
/** Collection routing (the notification-output posture). */
|
|
10110
10115
|
addonId: z.string().optional(),
|
|
@@ -10119,7 +10124,28 @@ var LlmGenerateBaseInputSchema = z.object({
|
|
|
10119
10124
|
jsonSchema: z.record(z.string(), z.unknown()).optional(),
|
|
10120
10125
|
/** Per-call override of the profile default. */
|
|
10121
10126
|
maxTokens: z.number().int().positive().optional(),
|
|
10122
|
-
temperature: z.number().optional()
|
|
10127
|
+
temperature: z.number().optional(),
|
|
10128
|
+
/** Per-call override of the profile default (nucleus sampling). */
|
|
10129
|
+
topP: z.number().min(0).max(1).optional(),
|
|
10130
|
+
/** Per-call override of the profile default (top-k sampling). */
|
|
10131
|
+
topK: z.number().int().positive().optional(),
|
|
10132
|
+
/** Per-call override of `profile.timeoutMs` — the total generation bound. */
|
|
10133
|
+
timeoutMs: z.number().int().positive().optional(),
|
|
10134
|
+
/** Per-call override; beats both the consumer table and the profile. */
|
|
10135
|
+
retry: LlmRetryPolicySchema.optional(),
|
|
10136
|
+
/**
|
|
10137
|
+
* Caller-minted id that makes this generation CANCELLABLE.
|
|
10138
|
+
*
|
|
10139
|
+
* Without it a caller that stops waiting cannot stop the work: the gates race
|
|
10140
|
+
* the call against 8 s and free their own slot when the timer wins, while the
|
|
10141
|
+
* generation upstream keeps running to `profile.timeoutMs` — 60 s by default,
|
|
10142
|
+
* on a single-threaded local model. The per-camera bound then counts WAITS,
|
|
10143
|
+
* not generations, and the real load is unbounded.
|
|
10144
|
+
*
|
|
10145
|
+
* `AbortSignal` cannot cross a process boundary; an id can. Pass one here and
|
|
10146
|
+
* `llm.cancel({ requestId })` tears the socket down.
|
|
10147
|
+
*/
|
|
10148
|
+
requestId: z.string().optional()
|
|
10123
10149
|
});
|
|
10124
10150
|
/**
|
|
10125
10151
|
* `llm-runtime` — node-side managed llama.cpp executor (spec §4). Registered
|
|
@@ -10132,6 +10158,18 @@ var LlmGenerateBaseInputSchema = z.object({
|
|
|
10132
10158
|
* Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
|
|
10133
10159
|
* watchdog — operator decision #3).
|
|
10134
10160
|
*/
|
|
10161
|
+
/**
|
|
10162
|
+
* A companion artifact that MUST land beside the main GGUF: the `mmproj`
|
|
10163
|
+
* projector of a vision model, or shards 2..N of a split GGUF. Carried on the
|
|
10164
|
+
* REF rather than looked up at install time, so what the operator approved in
|
|
10165
|
+
* the preview is exactly what the node downloads.
|
|
10166
|
+
*/
|
|
10167
|
+
var ManagedModelExtraFileSchema = z.object({
|
|
10168
|
+
url: z.string(),
|
|
10169
|
+
filename: z.string(),
|
|
10170
|
+
sizeBytes: z.number(),
|
|
10171
|
+
sha256: z.string().optional()
|
|
10172
|
+
});
|
|
10135
10173
|
var ManagedModelRefSchema = z.discriminatedUnion("kind", [
|
|
10136
10174
|
z.object({
|
|
10137
10175
|
kind: z.literal("catalog"),
|
|
@@ -10140,7 +10178,11 @@ var ManagedModelRefSchema = z.discriminatedUnion("kind", [
|
|
|
10140
10178
|
z.object({
|
|
10141
10179
|
kind: z.literal("url"),
|
|
10142
10180
|
url: z.string(),
|
|
10143
|
-
sha256: z.string().optional()
|
|
10181
|
+
sha256: z.string().optional(),
|
|
10182
|
+
/** Picker/status label; the file basename when absent. */
|
|
10183
|
+
label: z.string().optional(),
|
|
10184
|
+
sizeBytes: z.number().optional(),
|
|
10185
|
+
extraFiles: z.array(ManagedModelExtraFileSchema).optional()
|
|
10144
10186
|
}),
|
|
10145
10187
|
z.object({
|
|
10146
10188
|
kind: z.literal("path"),
|
|
@@ -10158,13 +10200,82 @@ var ManagedRuntimeConfigSchema = z.object({
|
|
|
10158
10200
|
gpuLayers: z.number().int().default(0),
|
|
10159
10201
|
/** Default: cpus-2, clamped ≥1 (resolved node-side). */
|
|
10160
10202
|
threads: z.number().int().optional(),
|
|
10161
|
-
/** Concurrent slots. */
|
|
10203
|
+
/** Concurrent slots (`--parallel`). */
|
|
10162
10204
|
parallel: z.number().int().default(1),
|
|
10205
|
+
/** Logical batch size (`-b`). Larger = faster prompt ingest, more RAM. */
|
|
10206
|
+
batchSize: z.number().int().positive().optional(),
|
|
10207
|
+
/** Physical batch / micro-batch (`-ub`). */
|
|
10208
|
+
ubatchSize: z.number().int().positive().optional(),
|
|
10209
|
+
/**
|
|
10210
|
+
* `--flash-attn`. Cuts KV-cache memory on the backends that implement it and
|
|
10211
|
+
* is a no-op elsewhere, so it is offered rather than assumed.
|
|
10212
|
+
*/
|
|
10213
|
+
flashAttention: z.boolean().default(false),
|
|
10214
|
+
/**
|
|
10215
|
+
* `--mlock`. Pins the weights in RAM so the OS cannot page them out mid
|
|
10216
|
+
* inference. Costs the full model size in resident memory — which is exactly
|
|
10217
|
+
* what the RAM budget is counting.
|
|
10218
|
+
*/
|
|
10219
|
+
mlock: z.boolean().default(false),
|
|
10220
|
+
/**
|
|
10221
|
+
* `--no-mmap`. Reads the whole GGUF up front instead of mapping it. Slower to
|
|
10222
|
+
* start, but avoids the page-fault stalls a network or spinning-disk model
|
|
10223
|
+
* store produces on every first token.
|
|
10224
|
+
*/
|
|
10225
|
+
noMmap: z.boolean().default(false),
|
|
10226
|
+
/** `--cache-type-k` / `--cache-type-v` — quantising the KV cache is the
|
|
10227
|
+
* cheapest way to fit a longer context in the same RAM. */
|
|
10228
|
+
cacheTypeK: z.enum([
|
|
10229
|
+
"f32",
|
|
10230
|
+
"f16",
|
|
10231
|
+
"q8_0",
|
|
10232
|
+
"q5_1",
|
|
10233
|
+
"q5_0",
|
|
10234
|
+
"q4_1",
|
|
10235
|
+
"q4_0"
|
|
10236
|
+
]).optional(),
|
|
10237
|
+
cacheTypeV: z.enum([
|
|
10238
|
+
"f32",
|
|
10239
|
+
"f16",
|
|
10240
|
+
"q8_0",
|
|
10241
|
+
"q5_1",
|
|
10242
|
+
"q5_0",
|
|
10243
|
+
"q4_1",
|
|
10244
|
+
"q4_0"
|
|
10245
|
+
]).optional(),
|
|
10246
|
+
/**
|
|
10247
|
+
* Escape hatch for llama-server flags this schema does NOT model — `--jinja`
|
|
10248
|
+
* (which most vision chat templates need and some language-only models
|
|
10249
|
+
* dislike), `--cont-batching`, `--rope-scaling`, …
|
|
10250
|
+
*
|
|
10251
|
+
* It is NOT a second place to set the flags above. A token that collides
|
|
10252
|
+
* with a typed field is REJECTED at start, naming the field that owns it
|
|
10253
|
+
* (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
|
|
10254
|
+
* the "two switches that disagree" failure this repo has already shipped
|
|
10255
|
+
* twice (D62).
|
|
10256
|
+
*/
|
|
10257
|
+
extraArgs: z.array(z.string()).default([]),
|
|
10163
10258
|
/** Else lazy: first generate boots it. */
|
|
10164
10259
|
autoStart: z.boolean().default(false),
|
|
10165
10260
|
/** 0 = never; frees RAM after quiet periods. */
|
|
10166
10261
|
idleStopMinutes: z.number().int().default(30)
|
|
10167
10262
|
});
|
|
10263
|
+
/**
|
|
10264
|
+
* Where a multi-GB install currently is. A single 0..1 fraction cannot answer
|
|
10265
|
+
* "is it stuck?" for an install that is three files (shards + mmproj) followed
|
|
10266
|
+
* by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
|
|
10267
|
+
* node looked hung. Phase + file + bytes is the smallest shape that does.
|
|
10268
|
+
*/
|
|
10269
|
+
var LlmDownloadProgressSchema = z.object({
|
|
10270
|
+
phase: z.enum(["downloading", "verifying"]),
|
|
10271
|
+
/** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
|
|
10272
|
+
file: z.string(),
|
|
10273
|
+
fileIndex: z.number().int(),
|
|
10274
|
+
fileCount: z.number().int(),
|
|
10275
|
+
/** Across the WHOLE install, not the current file. */
|
|
10276
|
+
downloadedBytes: z.number(),
|
|
10277
|
+
totalBytes: z.number().optional()
|
|
10278
|
+
});
|
|
10168
10279
|
var LlmRuntimeStatusSchema = z.object({
|
|
10169
10280
|
/** Status is ALWAYS node-qualified. */
|
|
10170
10281
|
nodeId: z.string(),
|
|
@@ -10181,6 +10292,8 @@ var LlmRuntimeStatusSchema = z.object({
|
|
|
10181
10292
|
modelPath: z.string().optional(),
|
|
10182
10293
|
modelId: z.string().optional(),
|
|
10183
10294
|
downloadProgress: z.number().min(0).max(1).optional(),
|
|
10295
|
+
/** Detail behind `downloadProgress`; present for the same lifetime. */
|
|
10296
|
+
download: LlmDownloadProgressSchema.optional(),
|
|
10184
10297
|
lastError: z.string().optional(),
|
|
10185
10298
|
crashesInWindow: z.number(),
|
|
10186
10299
|
/** Child RSS (sampled best-effort). */
|
|
@@ -10191,7 +10304,14 @@ var LlmNodeModelSchema = z.object({
|
|
|
10191
10304
|
file: z.string(),
|
|
10192
10305
|
sizeBytes: z.number(),
|
|
10193
10306
|
catalogId: z.string().optional(),
|
|
10194
|
-
installedAt: z.number().optional()
|
|
10307
|
+
installedAt: z.number().optional(),
|
|
10308
|
+
/**
|
|
10309
|
+
* Absolute path on the node. Present so a file that is on disk but matches
|
|
10310
|
+
* no catalog entry — a custom Hugging Face install, or a GGUF the operator
|
|
10311
|
+
* copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
|
|
10312
|
+
* it the picker could list such a file and do nothing with it.
|
|
10313
|
+
*/
|
|
10314
|
+
path: z.string().optional()
|
|
10195
10315
|
});
|
|
10196
10316
|
var LlmRuntimeDiskUsageSchema = z.object({
|
|
10197
10317
|
nodeId: z.string(),
|
|
@@ -10262,10 +10382,47 @@ var LlmProfileSchema = z.object({
|
|
|
10262
10382
|
baseUrl: z.string().optional(),
|
|
10263
10383
|
/** ConfigUISchema type:'password' — never round-trips (spec §5). */
|
|
10264
10384
|
apiKey: z.string().optional(),
|
|
10385
|
+
/** Vision on/off. A vision call against a `false` profile is REFUSED, never
|
|
10386
|
+
* degraded to text — that shipped once and produced a confident answer to a
|
|
10387
|
+
* question about a picture nobody sent. */
|
|
10265
10388
|
supportsVision: z.boolean(),
|
|
10266
10389
|
temperature: z.number().min(0).max(2).optional(),
|
|
10390
|
+
/** Nucleus sampling. Every wire we speak has it. */
|
|
10391
|
+
topP: z.number().min(0).max(1).optional(),
|
|
10392
|
+
/** Top-k sampling. Carried only by the wires that have it — NEITHER OpenAI
|
|
10393
|
+
* wire does, and the client drops it there (measured: the request body gets
|
|
10394
|
+
* `top_p` and no `top_k`). The profile editor hides the field wherever it
|
|
10395
|
+
* would change nothing; `KINDS_WITH_TOP_K` is the single owner of that list. */
|
|
10396
|
+
topK: z.number().int().positive().optional(),
|
|
10267
10397
|
maxTokens: z.number().int().positive().optional(),
|
|
10398
|
+
/** Prompt context window. Advisory for cloud kinds (they enforce their own);
|
|
10399
|
+
* for `managed-local` it is the llama.cpp `--ctx-size` the runtime starts
|
|
10400
|
+
* the model with, so it is the one field that changes a PROCESS. */
|
|
10401
|
+
contextLength: z.number().int().positive().optional(),
|
|
10402
|
+
/** Default system prompt. A caller's `system` REPLACES it (never appends —
|
|
10403
|
+
* two system prompts fighting is worse than either alone). */
|
|
10404
|
+
systemPrompt: z.string().optional(),
|
|
10405
|
+
/** Total generation bound — the only one a unary call has. */
|
|
10268
10406
|
timeoutMs: z.number().int().positive().default(6e4),
|
|
10407
|
+
/** The TCP handshake only — "is the port even open". NOT the wait for
|
|
10408
|
+
* response headers: on the LM Studio / llama-server wire those are written
|
|
10409
|
+
* once the model has finished loading, so they belong to the bound below. */
|
|
10410
|
+
connectTimeoutMs: z.number().int().positive().default(1e4),
|
|
10411
|
+
/** Accepted, but no output yet — response headers included, because a cold
|
|
10412
|
+
* GPU load is exactly what happens before them. */
|
|
10413
|
+
firstTokenTimeoutMs: z.number().int().positive().default(12e4),
|
|
10414
|
+
/** Output started then stopped. */
|
|
10415
|
+
idleTimeoutMs: z.number().int().positive().default(6e4),
|
|
10416
|
+
/** Profile-level default. The per-consumer table and a per-call override
|
|
10417
|
+
* both beat it — see `resolveRetryPolicy`. */
|
|
10418
|
+
retry: LlmRetryPolicySchema.default({
|
|
10419
|
+
enabled: false,
|
|
10420
|
+
maxAttempts: 1
|
|
10421
|
+
}),
|
|
10422
|
+
/** Whether this profile may use tools. The tool-call plumbing rides the
|
|
10423
|
+
* library; the REGISTRY of callable tools is ours and is empty in v1, so a
|
|
10424
|
+
* `true` here buys the wiring, not behaviour, until tools are registered. */
|
|
10425
|
+
toolsEnabled: z.boolean().default(false),
|
|
10269
10426
|
extraHeaders: z.record(z.string(), z.string()).optional(),
|
|
10270
10427
|
/** kind === 'managed-local' only (spec §4). */
|
|
10271
10428
|
runtime: ManagedRuntimeConfigSchema.optional()
|
|
@@ -10315,6 +10472,36 @@ var ManagedModelCatalogEntrySchema = z.object({
|
|
|
10315
10472
|
/** Vision models: companion projector file. */
|
|
10316
10473
|
mmprojUrl: z.string().optional()
|
|
10317
10474
|
});
|
|
10475
|
+
/**
|
|
10476
|
+
* The outcome of turning one operator-typed Hugging Face reference into a
|
|
10477
|
+
* download plan. A RESULT, never a throw: "this repo has 24 quantizations and
|
|
10478
|
+
* I will not pick for you" is a normal answer the UI has to render, not an
|
|
10479
|
+
* exception.
|
|
10480
|
+
*
|
|
10481
|
+
* `candidates` is the whole reason the refusal is usable — every string in it
|
|
10482
|
+
* is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
|
|
10483
|
+
*/
|
|
10484
|
+
var HfModelResolutionSchema = z.discriminatedUnion("ok", [z.object({
|
|
10485
|
+
ok: z.literal(true),
|
|
10486
|
+
/** Ready to hand to `installModel` unchanged. */
|
|
10487
|
+
model: ManagedModelRefSchema,
|
|
10488
|
+
label: z.string(),
|
|
10489
|
+
repo: z.string(),
|
|
10490
|
+
quantization: z.string(),
|
|
10491
|
+
purpose: z.enum(["text", "vision"]),
|
|
10492
|
+
totalBytes: z.number(),
|
|
10493
|
+
/** mmproj + shards, for the preview: an operator approving 23 GB should
|
|
10494
|
+
* see that 0.9 GB of it is a projector they did not name. */
|
|
10495
|
+
extraFilenames: z.array(z.string())
|
|
10496
|
+
}), z.object({
|
|
10497
|
+
ok: z.literal(false),
|
|
10498
|
+
code: z.string(),
|
|
10499
|
+
message: z.string(),
|
|
10500
|
+
candidates: z.array(z.string()).optional(),
|
|
10501
|
+
/** Set when the refusal was only the ceiling: re-calling with
|
|
10502
|
+
* `maxBytes: requiredBytes` is the operator's explicit override. */
|
|
10503
|
+
requiredBytes: z.number().optional()
|
|
10504
|
+
})]);
|
|
10318
10505
|
var LlmRuntimeNodeSchema = z.object({
|
|
10319
10506
|
nodeId: z.string(),
|
|
10320
10507
|
reachable: z.boolean(),
|
|
@@ -10338,6 +10525,17 @@ var llmCapability = {
|
|
|
10338
10525
|
methods: {
|
|
10339
10526
|
generate: method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }),
|
|
10340
10527
|
generateVision: method(GenerateVisionInputSchema, LlmGenerateResultSchema, { kind: "mutation" }),
|
|
10528
|
+
/**
|
|
10529
|
+
* Stop a generation started with a `requestId`.
|
|
10530
|
+
*
|
|
10531
|
+
* Idempotent and always successful: cancelling an id that already finished,
|
|
10532
|
+
* never existed, or was cancelled a moment ago is a no-op. A caller that has
|
|
10533
|
+
* given up must never have to handle an error from giving up.
|
|
10534
|
+
*/
|
|
10535
|
+
cancel: method(z.object({
|
|
10536
|
+
addonId: z.string().optional(),
|
|
10537
|
+
requestId: z.string()
|
|
10538
|
+
}), z.void(), { kind: "mutation" }),
|
|
10341
10539
|
listProfileKinds: method(z.object({}), z.array(LlmProfileKindDescriptorSchema)),
|
|
10342
10540
|
listProfiles: method(z.object({}), z.array(LlmProfileSchema)),
|
|
10343
10541
|
upsertProfile: method(z.object({ profile: LlmProfileSchema }), LlmProfileSchema, {
|
|
@@ -10371,6 +10569,25 @@ var llmCapability = {
|
|
|
10371
10569
|
listModelCatalog: method(z.object({}), z.array(ManagedModelCatalogEntrySchema)),
|
|
10372
10570
|
listRuntimeNodes: method(z.object({}), z.array(LlmRuntimeNodeSchema)),
|
|
10373
10571
|
listNodeModels: method(z.object({ nodeId: z.string() }), z.array(LlmNodeModelSchema)),
|
|
10572
|
+
/**
|
|
10573
|
+
* One typed Hugging Face reference → a pinned, verified `ManagedModelRef`.
|
|
10574
|
+
*
|
|
10575
|
+
* Runs on the HUB, not on the target node: resolution needs egress to
|
|
10576
|
+
* huggingface.co, and an agent that cannot reach it still installs fine
|
|
10577
|
+
* through the model-distributor relay. Nothing is downloaded here — this is
|
|
10578
|
+
* a tree read plus a HEAD, so the operator sees the size, the quantization
|
|
10579
|
+
* and the mmproj BEFORE approving a multi-GB pull.
|
|
10580
|
+
*/
|
|
10581
|
+
resolveModelRef: method(z.object({
|
|
10582
|
+
/** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
|
|
10583
|
+
* `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
|
|
10584
|
+
ref: z.string(),
|
|
10585
|
+
/** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
|
|
10586
|
+
maxBytes: z.number().positive().optional()
|
|
10587
|
+
}), HfModelResolutionSchema, {
|
|
10588
|
+
kind: "mutation",
|
|
10589
|
+
auth: "admin"
|
|
10590
|
+
}),
|
|
10374
10591
|
installModel: method(z.object({
|
|
10375
10592
|
nodeId: z.string(),
|
|
10376
10593
|
model: ManagedModelRefSchema
|
|
@@ -12312,28 +12529,36 @@ var NcOccupancyConditionSchema = z.object({
|
|
|
12312
12529
|
/**
|
|
12313
12530
|
* Audio condition (IMMEDIATE trigger) — a rule on SOUND, not on a picture.
|
|
12314
12531
|
*
|
|
12315
|
-
*
|
|
12316
|
-
*
|
|
12317
|
-
*
|
|
12318
|
-
*
|
|
12319
|
-
*
|
|
12320
|
-
*
|
|
12321
|
-
*
|
|
12322
|
-
*
|
|
12323
|
-
*
|
|
12324
|
-
*
|
|
12325
|
-
*
|
|
12326
|
-
*
|
|
12327
|
-
*
|
|
12328
|
-
*
|
|
12329
|
-
*
|
|
12330
|
-
*
|
|
12331
|
-
*
|
|
12332
|
-
*
|
|
12333
|
-
*
|
|
12334
|
-
*
|
|
12335
|
-
*
|
|
12336
|
-
* `
|
|
12532
|
+
* **TWO EXCLUSIVE MODES** (operator decision 2026-08-14, D157). Which one a
|
|
12533
|
+
* rule is in is not a stored field — it is WHICH FILTER the rule carries, so
|
|
12534
|
+
* there is no second switch that can disagree with the first and every rule
|
|
12535
|
+
* authored before the decision migrates for free (`audioModeOf`):
|
|
12536
|
+
*
|
|
12537
|
+
* - **LABEL mode — `labels` present.** The rule fires on the FIRST frame the
|
|
12538
|
+
* classifier labels with one of them. No window, no percentage:
|
|
12539
|
+
* `hitPercent` and `samplingSeconds` are ignored, and the rule's own
|
|
12540
|
+
* `throttle` cooldown is the only brake. The per-label confidence floor is
|
|
12541
|
+
* the analyzer's (`classificationMinScore`, per device) — a label only
|
|
12542
|
+
* reaches this condition if the classifier was already confident enough.
|
|
12543
|
+
* - **LEVEL mode — `dbThreshold` present, no labels.** The sampling window IS
|
|
12544
|
+
* the condition: at least `hitPercent`% of the samples over
|
|
12545
|
+
* `samplingSeconds` must be at or above `dbThreshold` dBFS (see
|
|
12546
|
+
* {@link NC_AUDIO_DBFS_FLOOR}: negative-going, `0` = full scale). The window
|
|
12547
|
+
* must be FULL before it can match — a window open for two of its ten
|
|
12548
|
+
* seconds is 100% of nothing.
|
|
12549
|
+
*
|
|
12550
|
+
* **Why label mode has no window.** It had one, and it never fired: the
|
|
12551
|
+
* analyzer emits ~1 audio frame per second but YAMNet only LABELS one to three
|
|
12552
|
+
* of them per episode, even through continuous crying. The measured maximum
|
|
12553
|
+
* `hitPercent` over the whole live history was 40 — under the shipped default
|
|
12554
|
+
* of 60, so a label rule could not fire at all, ever. A percentage of frames is
|
|
12555
|
+
* the wrong question to ask of a sparse classifier.
|
|
12556
|
+
*
|
|
12557
|
+
* **Fail-closed when NEITHER is given** — every sample would be a trivial hit
|
|
12558
|
+
* and the rule would fire on silence. The schema cannot express "exactly one
|
|
12559
|
+
* of" without becoming a ZodEffects the cap path would have to special-case, so
|
|
12560
|
+
* the exclusivity is enforced where every editor writes (`patchAudio`) and a
|
|
12561
|
+
* legacy rule carrying both resolves to LABEL (the mode that fires).
|
|
12337
12562
|
*
|
|
12338
12563
|
* Labels are the audio macro classes (`AUDIO_MACRO_LABELS` / the NC taxonomy's
|
|
12339
12564
|
* `audio-*` ids). Both spellings are accepted — the matcher normalizes the
|
|
@@ -12341,13 +12566,13 @@ var NcOccupancyConditionSchema = z.object({
|
|
|
12341
12566
|
* an operator who typed `dog` mean the same thing.
|
|
12342
12567
|
*/
|
|
12343
12568
|
var NcAudioConditionSchema = z.object({
|
|
12344
|
-
/**
|
|
12569
|
+
/** LABEL MODE: audio macro labels. Present ⇒ fires on the first labelled frame. */
|
|
12345
12570
|
labels: z.array(z.string().min(1)).min(1).optional(),
|
|
12346
|
-
/**
|
|
12571
|
+
/** LEVEL MODE: floor in dBFS (negative-going, `0` = full scale). */
|
|
12347
12572
|
dbThreshold: z.number().min(-96).max(0).optional(),
|
|
12348
|
-
/**
|
|
12573
|
+
/** LEVEL MODE ONLY: percentage of the window's samples that must be hits (1–100). */
|
|
12349
12574
|
hitPercent: z.number().int().min(1).max(100).default(60),
|
|
12350
|
-
/**
|
|
12575
|
+
/** LEVEL MODE ONLY: length of the sampling window in seconds. */
|
|
12351
12576
|
samplingSeconds: z.number().int().min(1).max(300).default(10)
|
|
12352
12577
|
});
|
|
12353
12578
|
/**
|
|
@@ -12500,9 +12725,66 @@ var NcDeviceStateConditionSchema = z.object({
|
|
|
12500
12725
|
/** Any of these matches. */
|
|
12501
12726
|
states: z.array(z.string().min(1)).min(1)
|
|
12502
12727
|
});
|
|
12728
|
+
/**
|
|
12729
|
+
* "This rule applies only while scene `sceneId` is `matched` / `diverged`."
|
|
12730
|
+
*
|
|
12731
|
+
* A GATE, not a trigger. `occupancy` and `audio` each DISCRIMINATE their rule —
|
|
12732
|
+
* carrying one makes the rule fire on that subject and nothing else. Scene is
|
|
12733
|
+
* the other shape entirely, the `deviceState` shape: it narrows a rule that
|
|
12734
|
+
* already has a trigger ("tell me about a person at the front door, but only
|
|
12735
|
+
* while the bin is still out"). That is why it composes with every delivery
|
|
12736
|
+
* instead of owning one, and why no new `NcDelivery` member and no new subject
|
|
12737
|
+
* kind exist for it — see D159.
|
|
12738
|
+
*
|
|
12739
|
+
* ── Identity ───────────────────────────────────────────────────────────────
|
|
12740
|
+
* `sceneId` is `SceneMonitor.id`, a `randomUUID()` minted by `createScene` —
|
|
12741
|
+
* globally unique, so it needs no device to disambiguate it. `deviceId` is
|
|
12742
|
+
* carried as a HINT for the editor and for the log line, never as part of the
|
|
12743
|
+
* lookup key: a rule whose hint drifted must still gate correctly.
|
|
12744
|
+
*
|
|
12745
|
+
* ── Which boolean ──────────────────────────────────────────────────────────
|
|
12746
|
+
* `latched` ABSENT means "whatever the scene itself says" — `SceneMonitor.emit`
|
|
12747
|
+
* already declares which boolean drives notification rules, and a second knob
|
|
12748
|
+
* that could disagree with it is exactly the D62 failure. Set it only to
|
|
12749
|
+
* override one rule against the scene's own default.
|
|
12750
|
+
*
|
|
12751
|
+
* - LIVE reading (`emit`/`latched` resolve to live): passes iff
|
|
12752
|
+
* `verdict === requiredState`. `unknown` — no reference for this light, view
|
|
12753
|
+
* shifted, no snapshot — passes NEITHER. A scene that cannot judge is not
|
|
12754
|
+
* evidence, in either direction.
|
|
12755
|
+
* - LATCHED reading: passes iff `latched === (requiredState === 'diverged')`.
|
|
12756
|
+
* The latch is a durable fact about the past ("it has diverged since I armed
|
|
12757
|
+
* it"), so a camera that has gone dark does not clear it — that is the whole
|
|
12758
|
+
* reason the operator asked for a latch.
|
|
12759
|
+
*
|
|
12760
|
+
* The gate reads an in-memory mirror (`NcSceneStateCache`) refreshed OFF the
|
|
12761
|
+
* event path, never the cap: D49. A mirror that has never loaded, or a scene it
|
|
12762
|
+
* does not carry, reads absent and the rule does NOT fire — fail closed, and
|
|
12763
|
+
* said out loud in the log rather than dropped in silence.
|
|
12764
|
+
*/
|
|
12765
|
+
var NcSceneConditionSchema = z.object({
|
|
12766
|
+
/** `SceneMonitor.id` — the uuid the cap mints. The whole lookup key. */
|
|
12767
|
+
sceneId: z.string().min(1),
|
|
12768
|
+
/** The camera the scene lives on. A hint for the editor and the log line. */
|
|
12769
|
+
deviceId: z.number().int().optional(),
|
|
12770
|
+
/** The state the scene must be in for the rule to fire. */
|
|
12771
|
+
requiredState: z.enum(["matched", "diverged"]),
|
|
12772
|
+
/**
|
|
12773
|
+
* Read the LATCH (`true`) or the LIVE verdict (`false`). Absent = follow the
|
|
12774
|
+
* scene's own `emit` field, which is the only place that decision belongs.
|
|
12775
|
+
*/
|
|
12776
|
+
latched: z.boolean().optional()
|
|
12777
|
+
});
|
|
12503
12778
|
var NcConditionsSchema = z.object({
|
|
12504
12779
|
/** Gate on ANOTHER device's current state (the alarm armed, a switch on). */
|
|
12505
12780
|
deviceState: NcDeviceStateConditionSchema.optional(),
|
|
12781
|
+
/**
|
|
12782
|
+
* Gate on a SCENE's state — "only while the bin is still out". Composes with
|
|
12783
|
+
* every trigger (detection, occupancy, audio, sensor, package, track-end);
|
|
12784
|
+
* unlike `occupancy`/`audio` it discriminates nothing. See
|
|
12785
|
+
* {@link NcSceneCondition} and D159.
|
|
12786
|
+
*/
|
|
12787
|
+
scene: NcSceneConditionSchema.optional(),
|
|
12506
12788
|
/** Device scope — absent = all devices. */
|
|
12507
12789
|
devices: z.array(z.number()).optional(),
|
|
12508
12790
|
/** Detector class names (any overlap with the record's class set). */
|
|
@@ -13140,6 +13422,7 @@ var NcConditionDescriptorSchema = z.object({
|
|
|
13140
13422
|
"occupancy",
|
|
13141
13423
|
"audio",
|
|
13142
13424
|
"deviceState",
|
|
13425
|
+
"scene",
|
|
13143
13426
|
"systemEvent"
|
|
13144
13427
|
]),
|
|
13145
13428
|
operator: z.enum([
|
|
@@ -16365,6 +16648,17 @@ var maxSessionHoldMsField = {
|
|
|
16365
16648
|
default: 12e4,
|
|
16366
16649
|
step: 5e3
|
|
16367
16650
|
};
|
|
16651
|
+
/**
|
|
16652
|
+
* Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
|
|
16653
|
+
* 5s so a rearm can never degenerate into per-event stream churn; default 90s
|
|
16654
|
+
* comfortably outlives the gap between two PIR wakes on a battery camera.
|
|
16655
|
+
*/
|
|
16656
|
+
var audioMotionWindowMsField = {
|
|
16657
|
+
min: 5e3,
|
|
16658
|
+
max: 6e5,
|
|
16659
|
+
default: 9e4,
|
|
16660
|
+
step: 5e3
|
|
16661
|
+
};
|
|
16368
16662
|
var motionFpsField = {
|
|
16369
16663
|
min: 1,
|
|
16370
16664
|
max: 30,
|
|
@@ -16541,6 +16835,27 @@ var RunnerCameraConfigSchema = z.object({
|
|
|
16541
16835
|
* resolved `CameraDetectionConfig`.
|
|
16542
16836
|
*/
|
|
16543
16837
|
maxSessionHoldMs: z.number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
|
|
16838
|
+
/**
|
|
16839
|
+
* Orchestrator-side quiet period (ms) that closes an `audioMode:
|
|
16840
|
+
* 'on-motion'` audio window, measured from the LAST motion event.
|
|
16841
|
+
*
|
|
16842
|
+
* This exists because the falling edge cannot be relied on. Camera-native
|
|
16843
|
+
* providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
|
|
16844
|
+
* its email-push SMTP path both emit `detected: true` and never the
|
|
16845
|
+
* counterpart); only the frame-diff analyzer emits falls. So on an
|
|
16846
|
+
* onboard-only camera a window that closed only on `detected: false` never
|
|
16847
|
+
* closed at all, and `on-motion` silently behaved as `always-on` — on a
|
|
16848
|
+
* battery camera, the one failure mode the mode exists to prevent.
|
|
16849
|
+
*
|
|
16850
|
+
* Every motion event rearms this timer WITHOUT restarting the stream, so a
|
|
16851
|
+
* burst of re-fires costs nothing. A falling edge, when one does arrive,
|
|
16852
|
+
* still closes earlier via `motionCooldownMs` — whichever comes first wins.
|
|
16853
|
+
*
|
|
16854
|
+
* Not consumed by the runner: carried here so it shares the per-camera
|
|
16855
|
+
* device-settings surface with `motionCooldownMs`, exactly like
|
|
16856
|
+
* `maxSessionHoldMs`.
|
|
16857
|
+
*/
|
|
16858
|
+
audioMotionWindowMs: z.number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
|
|
16544
16859
|
motionFps: z.number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
|
|
16545
16860
|
detectionFps: z.number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
|
|
16546
16861
|
motionStreamId: z.string(),
|
|
@@ -16636,7 +16951,7 @@ var RunnerCameraConfigSchema = z.object({
|
|
|
16636
16951
|
*/
|
|
16637
16952
|
inferenceDevices: z.array(RunnerInferenceDeviceSchema).readonly().optional()
|
|
16638
16953
|
});
|
|
16639
|
-
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
16954
|
+
motionFpsField.min, motionFpsField.max, motionFpsField.step, motionFpsField.default, detectionFpsField.min, detectionFpsField.max, detectionFpsField.step, detectionFpsField.default, motionCooldownMsField.min, motionCooldownMsField.max, motionCooldownMsField.step, motionCooldownMsField.default, maxSessionHoldMsField.min, maxSessionHoldMsField.max, maxSessionHoldMsField.step, maxSessionHoldMsField.default, audioMotionWindowMsField.min, audioMotionWindowMsField.max, audioMotionWindowMsField.step, audioMotionWindowMsField.default, occupancyRecheckSecField.min, occupancyRecheckSecField.max, occupancyRecheckSecField.step, occupancyRecheckSecField.default, occupancyRecheckFramesField.min, occupancyRecheckFramesField.max, occupancyRecheckFramesField.step, occupancyRecheckFramesField.default;
|
|
16640
16955
|
/**
|
|
16641
16956
|
* Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
|
|
16642
16957
|
* load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
|
|
@@ -26642,10 +26957,22 @@ var recordingExportCapability = {
|
|
|
26642
26957
|
* thing except the comparator: `similarity` (CLIP cosine at the same ROI coords
|
|
26643
26958
|
* vs condition-tagged references) and `llm` (vision-LLM judgment over the crop).
|
|
26644
26959
|
*
|
|
26645
|
-
*
|
|
26646
|
-
*
|
|
26647
|
-
*
|
|
26648
|
-
*
|
|
26960
|
+
* **No `deviceConfig`, deliberately.** This shipped as the D14 widget archetype,
|
|
26961
|
+
* which put a "Scenes" tab on one camera's detail page. That is the wrong shape
|
|
26962
|
+
* for the thing: a scene is a standing question about the property ("is the bin
|
|
26963
|
+
* still out"), and the operator's question is "which of my scenes have tripped",
|
|
26964
|
+
* across every camera at once — not "what does camera 617 think". Buried one
|
|
26965
|
+
* camera deep it also could not be found. The surface is now a top-level admin
|
|
26966
|
+
* page (`/scenes`, `pages/Scenes.tsx`) that lists every scene on every camera and
|
|
26967
|
+
* picks the camera inside the create flow, the same shape Events and Faces have.
|
|
26968
|
+
*
|
|
26969
|
+
* The consequence to keep in mind: `host/scene-monitor-editor` is gone from
|
|
26970
|
+
* `HOST_WIDGETS` too. `scripts/check-host-widget-resolves.ts` asserts BOTH
|
|
26971
|
+
* directions, so a registration nobody declares fails exactly as loudly as a
|
|
26972
|
+
* declaration nobody registers. The editor is imported directly by the page.
|
|
26973
|
+
*
|
|
26974
|
+
* `status.kind:'push'` — the engine pushes on every hysteresis flip /
|
|
26975
|
+
* availability change; consumers never poll.
|
|
26649
26976
|
*/
|
|
26650
26977
|
/** Extensible condition tag. Seeded 'day' | 'ir' (the two variants the operator
|
|
26651
26978
|
* captures) plus 'night' | 'dawn' | 'dusk' from the resolver's sun-times band.
|
|
@@ -26656,6 +26983,33 @@ var recordingExportCapability = {
|
|
|
26656
26983
|
* as `unknown`, never guessed. A day reference scored against an IR frame
|
|
26657
26984
|
* collapses the cosine and would latch a false alarm every single night. */
|
|
26658
26985
|
var SceneConditionSchema = z.string();
|
|
26986
|
+
/**
|
|
26987
|
+
* What a scene does when the CURRENT light has no reference of its own.
|
|
26988
|
+
*
|
|
26989
|
+
* The lighting variants are not equally likely to exist. Almost every operator
|
|
26990
|
+
* captures daylight and then never stands outside at 22:00 to capture IR, and a
|
|
26991
|
+
* scene that is only ever going to be asked about a daytime question ("is the
|
|
26992
|
+
* bin still on the kerb at 08:00") does not need a night reference at all. The
|
|
26993
|
+
* night half must therefore be OPTIONAL, and optional means the scene keeps
|
|
26994
|
+
* working without it rather than degrading into a permanent complaint.
|
|
26995
|
+
*
|
|
26996
|
+
* - `skip` (default) — the check in that light is not made. Not a verdict, not
|
|
26997
|
+
* an alarm, not even an `unknown`: the live state simply stays whatever the
|
|
26998
|
+
* last covered light left it at, the latch is untouched, and the hysteresis
|
|
26999
|
+
* run is neither spent nor cleared. The scene resumes by itself at first
|
|
27000
|
+
* light. This is the only behaviour under which "I never captured IR" is a
|
|
27001
|
+
* configuration choice instead of a nightly fault.
|
|
27002
|
+
* - `judge-anyway` — score against the OTHER conditions' references. Available
|
|
27003
|
+
* for cameras whose IR frame is close enough to daylight (a floodlit
|
|
27004
|
+
* driveway, an always-white-light doorbell), and wrong for everything else:
|
|
27005
|
+
* cross-condition cosines are not comparable, so a day reference against a
|
|
27006
|
+
* true IR frame collapses and the scene reports a theft at 21:40.
|
|
27007
|
+
*
|
|
27008
|
+
* Never applies when the scene has NO comparable reference at all — that is
|
|
27009
|
+
* "not armed yet", it is reported as `no-reference-for-condition`, and silence
|
|
27010
|
+
* there would hide a scene the operator never finished setting up.
|
|
27011
|
+
*/
|
|
27012
|
+
var SceneUncoveredPolicySchema = z.enum(["skip", "judge-anyway"]);
|
|
26659
27013
|
/** `matched` = the baseline is what we see; `diverged` = it demonstrably is not;
|
|
26660
27014
|
* `unknown` = we cannot judge (no reference for this condition, encoder model
|
|
26661
27015
|
* changed, view shifted, no snapshot). `unknown` is a real value, not a null,
|
|
@@ -26711,6 +27065,9 @@ var SceneCheckSchema = z.discriminatedUnion("mode", [z.object({
|
|
|
26711
27065
|
hysteresisCount: z.number().int().positive()
|
|
26712
27066
|
})]);
|
|
26713
27067
|
var SCENE_DEFAULT_ANCHOR_THRESHOLD = .85;
|
|
27068
|
+
/** Night is OPTIONAL. A scene with only a daylight reference sits the IR hours
|
|
27069
|
+
* out in silence rather than reporting a fault every night. */
|
|
27070
|
+
var SCENE_DEFAULT_UNCOVERED_POLICY = "skip";
|
|
26714
27071
|
/**
|
|
26715
27072
|
* Vision-model adjudication of a candidate flip. Field names deliberately
|
|
26716
27073
|
* mirror `NcConfirmSchema` so an operator meets one vocabulary, not two.
|
|
@@ -26777,6 +27134,21 @@ var SceneMonitorSchema = z.object({
|
|
|
26777
27134
|
* automation can react to the bin coming back without the operator's own
|
|
26778
27135
|
* alarm silently clearing itself. */
|
|
26779
27136
|
autoRestore: z.boolean().default(false),
|
|
27137
|
+
/** What to do when the current light has no reference of its own. See
|
|
27138
|
+
* {@link SceneUncoveredPolicySchema} — the default makes night OPTIONAL. */
|
|
27139
|
+
onUncoveredCondition: SceneUncoveredPolicySchema.default(SCENE_DEFAULT_UNCOVERED_POLICY),
|
|
27140
|
+
/**
|
|
27141
|
+
* The light whose checks are currently being SAT OUT under
|
|
27142
|
+
* `onUncoveredCondition: 'skip'` — `null` when the scene is checking normally.
|
|
27143
|
+
*
|
|
27144
|
+
* Engine-reported and advisory only: it moves no verdict, no latch and no
|
|
27145
|
+
* hysteresis. It exists so the card can say *"night (IR) — checks paused,
|
|
27146
|
+
* nothing captured in this light"* in the same calm voice as the coverage
|
|
27147
|
+
* line, because the alternative is a scene that silently stops answering
|
|
27148
|
+
* after sunset with nothing anywhere saying why. A skipped check must never
|
|
27149
|
+
* read as a broken one.
|
|
27150
|
+
*/
|
|
27151
|
+
suspendedCondition: SceneConditionSchema.nullable().default(null),
|
|
26780
27152
|
/** Named cause when `verdict === 'unknown'`. */
|
|
26781
27153
|
unavailable: SceneUnavailableSchema.nullable(),
|
|
26782
27154
|
/** Conditions that have at least one comparable reference — the coverage line
|
|
@@ -26794,12 +27166,6 @@ var sceneMonitorCapability = {
|
|
|
26794
27166
|
kind: "wrapper",
|
|
26795
27167
|
defaultActive: true,
|
|
26796
27168
|
deviceTypes: [DeviceType.Camera],
|
|
26797
|
-
deviceConfig: { ui: {
|
|
26798
|
-
kind: "widget",
|
|
26799
|
-
widgetId: "host/scene-monitor-editor",
|
|
26800
|
-
tab: "scenes",
|
|
26801
|
-
label: "Scenes"
|
|
26802
|
-
} },
|
|
26803
27169
|
methods: {
|
|
26804
27170
|
listScenes: method(z.object({ deviceId: z.number() }), SceneMonitorStatusSchema),
|
|
26805
27171
|
createScene: method(z.object({
|
|
@@ -26836,6 +27202,7 @@ var sceneMonitorCapability = {
|
|
|
26836
27202
|
minObservationSpacingSec: z.number().int().min(0).max(3600).optional(),
|
|
26837
27203
|
anchorThreshold: z.number().min(0).max(1).optional(),
|
|
26838
27204
|
autoRestore: z.boolean().optional(),
|
|
27205
|
+
onUncoveredCondition: SceneUncoveredPolicySchema.optional(),
|
|
26839
27206
|
/** `null` clears the vision-model adjudicator. */
|
|
26840
27207
|
confirm: SceneConfirmSchema.nullable().optional()
|
|
26841
27208
|
})
|
|
@@ -27658,6 +28025,61 @@ var NetworkAddressSchema = z.object({
|
|
|
27658
28025
|
family: z.string(),
|
|
27659
28026
|
internal: z.boolean()
|
|
27660
28027
|
});
|
|
28028
|
+
/**
|
|
28029
|
+
* Provenance of the site coordinates, and the whole reason this is not just two
|
|
28030
|
+
* numbers.
|
|
28031
|
+
*
|
|
28032
|
+
* - `operator-set` — a human typed it, or accepted a detection. Authoritative;
|
|
28033
|
+
* nothing overwrites it.
|
|
28034
|
+
* - `derived-from-ip` — the hub geolocated its own public IP once, because a
|
|
28035
|
+
* default that is right to a few kilometres beats the coarse UTC clock split
|
|
28036
|
+
* the sun-times consumers otherwise fall back to.
|
|
28037
|
+
*
|
|
28038
|
+
* The UI shows which one it is. An operator who cannot tell a guess from their
|
|
28039
|
+
* own input will eventually trust the guess.
|
|
28040
|
+
*/
|
|
28041
|
+
var SiteLocationSourceSchema = z.enum(["operator-set", "derived-from-ip"]);
|
|
28042
|
+
/**
|
|
28043
|
+
* Where the installation physically is — a fact of the SITE, not of any addon.
|
|
28044
|
+
*
|
|
28045
|
+
* It used to live in `pipeline-analytics`' global settings, which made a
|
|
28046
|
+
* property of the building a property of one analytics addon. Anything that
|
|
28047
|
+
* needs sun-times (scene condition variants today; anything solar tomorrow)
|
|
28048
|
+
* reads it from here.
|
|
28049
|
+
*/
|
|
28050
|
+
var SiteLocationSchema = z.object({
|
|
28051
|
+
/** WGS84 decimal degrees. */
|
|
28052
|
+
latitude: z.number().min(-90).max(90),
|
|
28053
|
+
longitude: z.number().min(-180).max(180),
|
|
28054
|
+
source: SiteLocationSourceSchema,
|
|
28055
|
+
/** Epoch ms the value was last written. */
|
|
28056
|
+
updatedAt: z.number(),
|
|
28057
|
+
/**
|
|
28058
|
+
* Human-readable place the geo-IP service reported ("Napoli, IT"). Display
|
|
28059
|
+
* only — never parsed, never matched on. Absent for an operator-typed value.
|
|
28060
|
+
*/
|
|
28061
|
+
label: z.string().optional()
|
|
28062
|
+
});
|
|
28063
|
+
/**
|
|
28064
|
+
* The read shape: the location plus the honest state of the one-shot derivation.
|
|
28065
|
+
*
|
|
28066
|
+
* `derivationAttemptedAt` is what makes the "one call, ever" contract
|
|
28067
|
+
* inspectable. When it is set and `location` is null, the geo-IP lookup ran and
|
|
28068
|
+
* failed; the hub will NOT try again on its own — the fallback is declared
|
|
28069
|
+
* (consumers degrade to their own last resort) and the operator either types the
|
|
28070
|
+
* coordinates or presses detect.
|
|
28071
|
+
*/
|
|
28072
|
+
var SiteLocationStatusSchema = z.object({
|
|
28073
|
+
location: SiteLocationSchema.nullable(),
|
|
28074
|
+
derivationAttemptedAt: z.number().nullable(),
|
|
28075
|
+
/** Why the last derivation failed, for the UI to show instead of a shrug. */
|
|
28076
|
+
derivationError: z.string().nullable()
|
|
28077
|
+
});
|
|
28078
|
+
/** `null` clears the location and re-arms nothing — the derivation stays spent. */
|
|
28079
|
+
var SetSiteLocationInputSchema = z.object({
|
|
28080
|
+
latitude: z.number().min(-90).max(90),
|
|
28081
|
+
longitude: z.number().min(-180).max(180)
|
|
28082
|
+
}).nullable();
|
|
27661
28083
|
var systemCapability = {
|
|
27662
28084
|
name: "system",
|
|
27663
28085
|
scope: "system",
|
|
@@ -27675,6 +28097,32 @@ var systemCapability = {
|
|
|
27675
28097
|
forceRetentionCleanup: method(z.void(), z.void(), {
|
|
27676
28098
|
kind: "mutation",
|
|
27677
28099
|
auth: "admin"
|
|
28100
|
+
}),
|
|
28101
|
+
/**
|
|
28102
|
+
* The site coordinates, deriving a default from the hub's public IP on the
|
|
28103
|
+
* FIRST read that finds nothing stored.
|
|
28104
|
+
*
|
|
28105
|
+
* The derivation is one-shot and bounded: one outbound request, a few
|
|
28106
|
+
* seconds, its outcome persisted either way. A hub with no internet pays it
|
|
28107
|
+
* once and never again, and neither boot nor any consumer is blocked on it —
|
|
28108
|
+
* the caller gets `location: null` and degrades exactly as it did before this
|
|
28109
|
+
* method existed.
|
|
28110
|
+
*/
|
|
28111
|
+
getSiteLocation: method(z.void(), SiteLocationStatusSchema),
|
|
28112
|
+
/** Operator input. Always lands as `source: 'operator-set'`. */
|
|
28113
|
+
setSiteLocation: method(SetSiteLocationInputSchema, SiteLocationStatusSchema, {
|
|
28114
|
+
kind: "mutation",
|
|
28115
|
+
auth: "admin"
|
|
28116
|
+
}),
|
|
28117
|
+
/**
|
|
28118
|
+
* Re-run the geo-IP derivation now. The ONLY way a spent or failed
|
|
28119
|
+
* derivation is retried — there is no timer, and no read path retries.
|
|
28120
|
+
* Overwrites an existing `derived-from-ip` value; refuses to clobber an
|
|
28121
|
+
* `operator-set` one.
|
|
28122
|
+
*/
|
|
28123
|
+
detectSiteLocation: method(z.void(), SiteLocationStatusSchema, {
|
|
28124
|
+
kind: "mutation",
|
|
28125
|
+
auth: "admin"
|
|
27678
28126
|
})
|
|
27679
28127
|
},
|
|
27680
28128
|
/** BIG PLAN 2: declarative mount hint — read by `@camstack/system` `buildCapRouters`. */
|
|
@@ -31410,6 +31858,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
31410
31858
|
addonId: null,
|
|
31411
31859
|
access: "create"
|
|
31412
31860
|
},
|
|
31861
|
+
"llm.cancel": {
|
|
31862
|
+
capName: "llm",
|
|
31863
|
+
capScope: "system",
|
|
31864
|
+
addonId: null,
|
|
31865
|
+
access: "create"
|
|
31866
|
+
},
|
|
31413
31867
|
"llm.deleteModel": {
|
|
31414
31868
|
capName: "llm",
|
|
31415
31869
|
capScope: "system",
|
|
@@ -31494,6 +31948,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
31494
31948
|
addonId: null,
|
|
31495
31949
|
access: "view"
|
|
31496
31950
|
},
|
|
31951
|
+
"llm.resolveModelRef": {
|
|
31952
|
+
capName: "llm",
|
|
31953
|
+
capScope: "system",
|
|
31954
|
+
addonId: null,
|
|
31955
|
+
access: "create"
|
|
31956
|
+
},
|
|
31497
31957
|
"llm.setDefault": {
|
|
31498
31958
|
capName: "llm",
|
|
31499
31959
|
capScope: "system",
|
|
@@ -34344,6 +34804,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
34344
34804
|
addonId: null,
|
|
34345
34805
|
access: "create"
|
|
34346
34806
|
},
|
|
34807
|
+
"system.detectSiteLocation": {
|
|
34808
|
+
capName: "system",
|
|
34809
|
+
capScope: "system",
|
|
34810
|
+
addonId: null,
|
|
34811
|
+
access: "create"
|
|
34812
|
+
},
|
|
34347
34813
|
"system.featureFlags": {
|
|
34348
34814
|
capName: "system",
|
|
34349
34815
|
capScope: "system",
|
|
@@ -34362,6 +34828,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
34362
34828
|
addonId: null,
|
|
34363
34829
|
access: "view"
|
|
34364
34830
|
},
|
|
34831
|
+
"system.getSiteLocation": {
|
|
34832
|
+
capName: "system",
|
|
34833
|
+
capScope: "system",
|
|
34834
|
+
addonId: null,
|
|
34835
|
+
access: "view"
|
|
34836
|
+
},
|
|
34365
34837
|
"system.health": {
|
|
34366
34838
|
capName: "system",
|
|
34367
34839
|
capScope: "system",
|
|
@@ -34386,6 +34858,12 @@ var METHOD_ACCESS_MAP = Object.freeze({
|
|
|
34386
34858
|
addonId: null,
|
|
34387
34859
|
access: "create"
|
|
34388
34860
|
},
|
|
34861
|
+
"system.setSiteLocation": {
|
|
34862
|
+
capName: "system",
|
|
34863
|
+
capScope: "system",
|
|
34864
|
+
addonId: null,
|
|
34865
|
+
access: "create"
|
|
34866
|
+
},
|
|
34389
34867
|
"terminalSession.adoptLegacyMonitor": {
|
|
34390
34868
|
capName: "terminal-session",
|
|
34391
34869
|
capScope: "system",
|