@camstack/addon-admin-ui 1.2.61 → 1.2.63
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/assets/{AddLocationWizard-BVrPN8yV.js → AddLocationWizard-DL-p2pfI.js} +1 -1
- package/dist/assets/{AddonCollectionPage-Cluggqrl.js → AddonCollectionPage-GmBzeWfb.js} +1 -1
- package/dist/assets/{Addons-pf4_6Np6.js → Addons-DJZ0fLKa.js} +1 -1
- package/dist/assets/{AdminTabs-D4DXIa-o.js → AdminTabs-BJAp46Yc.js} +1 -1
- package/dist/assets/AiProfiles-Dr3P3tTd.js +3 -0
- package/dist/assets/{BrokerForm-DpZEb2oo.js → BrokerForm-B5lFCkpx.js} +1 -1
- package/dist/assets/{Build-DFf7JJQN.js → Build-BF5TjhPZ.js} +1 -1
- package/dist/assets/{Capabilities-fyyhemKk.js → Capabilities-dM4kxoPi.js} +1 -1
- package/dist/assets/{CapabilityBadges-CFAqIVEN.js → CapabilityBadges-BXTtPMj5.js} +1 -1
- package/dist/assets/{Cluster-BI79yXHi.js → Cluster-Bc9KL5vo.js} +1 -1
- package/dist/assets/{Data-BnH1FBcv.js → Data-Ck3PTxjk.js} +1 -1
- package/dist/assets/{DetectionIntelligence-pZ34_QKw.js → DetectionIntelligence-CQAuuHZJ.js} +1 -1
- package/dist/assets/{DeviceAggregateSection-DcU4HtPo.js → DeviceAggregateSection-BUdjIJ3K.js} +1 -1
- package/dist/assets/{DeviceDetail-D4IEMIPA.js → DeviceDetail-BcCMnGp5.js} +1 -1
- package/dist/assets/{Devices-Qvmjz6OV.js → Devices-BcsFIXeR.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-BiOYECZo.js → EmbedPlayerPage-BvDdFRwh.js} +1 -1
- package/dist/assets/{Events-BkGGzjc6.js → Events-BPJx8pMN.js} +1 -1
- package/dist/assets/{FormBuilder-Ce9uWxtp.js → FormBuilder-eO_2opNc.js} +1 -1
- package/dist/assets/{Identity-Dz2q6O35.js → Identity-cScC97Mq.js} +1 -1
- package/dist/assets/{IntegrationDetail-BgYnCOqc.js → IntegrationDetail-BrI5QbcU.js} +1 -1
- package/dist/assets/{Integrations-JZkpFkbO.js → Integrations-BDRRlSaJ.js} +1 -1
- package/dist/assets/{Integrations-CGDgpbY3.js → Integrations-DJuPZXOa.js} +1 -1
- package/dist/assets/{Logs-Dc8myuGB.js → Logs-DgjSPchK.js} +1 -1
- package/dist/assets/{MotionZonesSettings-CNAneuwi.js → MotionZonesSettings-B2pHjyow.js} +1 -1
- package/dist/assets/{MyAccess-BplkKorv.js → MyAccess-Cb_qTJZZ.js} +1 -1
- package/dist/assets/{Network-DkXgbHRL.js → Network-Bc4x3mCD.js} +1 -1
- package/dist/assets/{NodeAddonsSettingsPanel-qSFnzXqZ.js → NodeAddonsSettingsPanel-S9qh9oix.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-B7RYmrXb.js → NodeInferenceDevices-egUQGuFl.js} +1 -1
- package/dist/assets/Notifications-1ARXHzBI.js +1 -0
- package/dist/assets/{Pipeline-BVix_5wm.js → Pipeline-D1NEy1ZN.js} +1 -1
- package/dist/assets/{Plates-Cn1Al2WA.js → Plates-WUDggEuV.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-GAkxAsA3.js → PrivacyMaskSettings-x5jpJN6L.js} +1 -1
- package/dist/assets/{ProviderIcon-CQo4yDQS.js → ProviderIcon-C5_0vsMH.js} +1 -1
- package/dist/assets/{Recordings-DZMmDA_4.js → Recordings-CiwNtOmP.js} +1 -1
- package/dist/assets/{ScanNetworkModal-TrU5QhWB.js → ScanNetworkModal-CuyJeqBI.js} +1 -1
- package/dist/assets/SceneMonitorEditor-lhBYjABG.js +1 -0
- package/dist/assets/{Scenes-bMn8sgm0.js → Scenes-DGv23Apk.js} +1 -1
- package/dist/assets/{Settings-B1YsrVcn.js → Settings-DG4iqZOC.js} +1 -1
- package/dist/assets/{Showroom-Cik2ivrC.js → Showroom-BdcMmdVm.js} +1 -1
- package/dist/assets/{Terminal-BWct2hhL.js → Terminal-Cll24Ext.js} +1 -1
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-B59PxHv9.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CWCjzW96.js} +1 -1
- package/dist/assets/{bell-ring-CtdRZtjG.js → bell-ring-_rBBDOOp.js} +1 -1
- package/dist/assets/{boxes-BN_wTQoj.js → boxes-D21_Gtau.js} +1 -1
- package/dist/assets/{build-cluster-graph-JVj1fl5o.js → build-cluster-graph-B2YakfxI.js} +1 -1
- package/dist/assets/circle-check-big-CdgHxf2K.js +1 -0
- package/dist/assets/{circle-x-DKEv2fk-.js → circle-x-Dme7swuV.js} +1 -1
- package/dist/assets/clock-LRrp-sNT.js +1 -0
- package/dist/assets/{copy-C0Y9pMFE.js → copy-D-RYlseV.js} +1 -1
- package/dist/assets/{debounced-invalidate-CYoigLZW.js → debounced-invalidate-DUItRp3z.js} +1 -1
- package/dist/assets/dist-B2dk3x-1.js +345 -0
- package/dist/assets/{dist-DVOPUibu.js → dist-DM5W_-lf.js} +1 -1
- package/dist/assets/{download-B538th-h.js → download-2daKodbc.js} +1 -1
- package/dist/assets/{face-bbox-0omHJ2v9.js → face-bbox-C1EmZtcs.js} +1 -1
- package/dist/assets/{hard-drive-DFBgqBxK.js → hard-drive-CN2O-rzf.js} +1 -1
- package/dist/assets/{hostInit-CiIhfzzr.js → hostInit-CIIBSAj3.js} +1 -1
- package/dist/assets/{index-Dr-ap6SH.js → index-D9F3sdd-.js} +3 -3
- package/dist/assets/{key-round-D1XSxvLS.js → key-round-Bq2pdPu0.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-82869dcc.js → mf-entry-bootstrap-0-e5e0dfd2.js} +2 -2
- package/dist/assets/{pencil-CZ2gMyTB.js → pencil-DA48cMNw.js} +1 -1
- package/dist/assets/play-Bg5-lqI9.js +1 -0
- package/dist/assets/player-overlays-DG8Qq2SN.js +1 -0
- package/dist/assets/plus-B17_qT4q.js +1 -0
- package/dist/assets/power-B3ls9EjL.js +1 -0
- package/dist/assets/{radio-C0T0_Ki5.js → radio-D5YXD5Mk.js} +1 -1
- package/dist/assets/{refresh-cw-DuE4ONv-.js → refresh-cw-CeN01FBy.js} +1 -1
- package/dist/assets/remoteEntry-CmQ-DXMH.js +1 -0
- package/dist/assets/rotate-ccw-DdaLkN93.js +1 -0
- package/dist/assets/rotate-cw-DiDpzlTp.js +1 -0
- package/dist/assets/search-5IKob3Pf.js +1 -0
- package/dist/assets/{send-CiGeFhM_.js → send-DtoGJcOc.js} +1 -1
- package/dist/assets/{server-BBJTl0ih.js → server-DVYSamal.js} +1 -1
- package/dist/assets/square-BSJyk4ja.js +1 -0
- package/dist/assets/{square-check-big-DEpi1DZf.js → square-check-big-BVgrKc-i.js} +1 -1
- package/dist/assets/src-B2p9OhlL.js +345 -0
- package/dist/assets/src-DpB-8ADl.js +67 -0
- package/dist/assets/{undo-2-BEASNScj.js → undo-2-RQcgGfE7.js} +1 -1
- package/dist/assets/{upload-CCWw0hX4.js → upload-CIlYkZ_R.js} +1 -1
- package/dist/assets/{use-scenes-feed-BrAVTu20.js → use-scenes-feed-asIA0HHK.js} +1 -1
- package/dist/assets/{useEventInvalidation-CnCqhaHZ.js → useEventInvalidation-C4hcZ266.js} +1 -1
- package/dist/assets/{video-BEAVV4bf.js → video-C0rp1BOP.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-D8I8UoDY.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-8FeeO_xT.js} +2 -2
- package/dist/assets/{wifi-sgX03Yna.js → wifi-CEXNRrIb.js} +1 -1
- package/dist/assets/{zap-DVVII2tr.js → zap-DZBO_poe.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +185 -6
- package/package.json +1 -1
- package/dist/assets/AiProfiles-Dc-3w9Z5.js +0 -3
- package/dist/assets/Notifications-CsUJcPdF.js +0 -1
- package/dist/assets/SceneMonitorEditor-DcTfkrW3.js +0 -1
- package/dist/assets/circle-check-big-KvCernzh.js +0 -1
- package/dist/assets/clock-Ddu_eThB.js +0 -1
- package/dist/assets/dist-Bz6O5BsH.js +0 -345
- package/dist/assets/play-BrdA8mXB.js +0 -1
- package/dist/assets/player-overlays-7AKPeTm-.js +0 -1
- package/dist/assets/plus-ChsVL8uT.js +0 -1
- package/dist/assets/power-Dz2il9ai.js +0 -1
- package/dist/assets/remoteEntry-CgpjK5QJ.js +0 -1
- package/dist/assets/rotate-ccw-DS5e2J2f.js +0 -1
- package/dist/assets/rotate-cw-Bb9OhnRT.js +0 -1
- package/dist/assets/search-BunRfhTv.js +0 -1
- package/dist/assets/square-BlgtgcV9.js +0 -1
- package/dist/assets/src-BaVKQIP9.js +0 -345
- package/dist/assets/src-CgOOvCVA.js +0 -67
package/dist/server/addon.js
CHANGED
|
@@ -12244,6 +12244,18 @@ var LlmGenerateBaseInputSchema = object({
|
|
|
12244
12244
|
* Resource ceiling = llama-server flags + idleStopMinutes ONLY (no RSS
|
|
12245
12245
|
* watchdog — operator decision #3).
|
|
12246
12246
|
*/
|
|
12247
|
+
/**
|
|
12248
|
+
* A companion artifact that MUST land beside the main GGUF: the `mmproj`
|
|
12249
|
+
* projector of a vision model, or shards 2..N of a split GGUF. Carried on the
|
|
12250
|
+
* REF rather than looked up at install time, so what the operator approved in
|
|
12251
|
+
* the preview is exactly what the node downloads.
|
|
12252
|
+
*/
|
|
12253
|
+
var ManagedModelExtraFileSchema = object({
|
|
12254
|
+
url: string(),
|
|
12255
|
+
filename: string(),
|
|
12256
|
+
sizeBytes: number(),
|
|
12257
|
+
sha256: string().optional()
|
|
12258
|
+
});
|
|
12247
12259
|
var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
12248
12260
|
object({
|
|
12249
12261
|
kind: literal("catalog"),
|
|
@@ -12252,7 +12264,11 @@ var ManagedModelRefSchema = discriminatedUnion("kind", [
|
|
|
12252
12264
|
object({
|
|
12253
12265
|
kind: literal("url"),
|
|
12254
12266
|
url: string(),
|
|
12255
|
-
sha256: string().optional()
|
|
12267
|
+
sha256: string().optional(),
|
|
12268
|
+
/** Picker/status label; the file basename when absent. */
|
|
12269
|
+
label: string().optional(),
|
|
12270
|
+
sizeBytes: number().optional(),
|
|
12271
|
+
extraFiles: array(ManagedModelExtraFileSchema).optional()
|
|
12256
12272
|
}),
|
|
12257
12273
|
object({
|
|
12258
12274
|
kind: literal("path"),
|
|
@@ -12313,11 +12329,39 @@ var ManagedRuntimeConfigSchema = object({
|
|
|
12313
12329
|
"q4_1",
|
|
12314
12330
|
"q4_0"
|
|
12315
12331
|
]).optional(),
|
|
12332
|
+
/**
|
|
12333
|
+
* Escape hatch for llama-server flags this schema does NOT model — `--jinja`
|
|
12334
|
+
* (which most vision chat templates need and some language-only models
|
|
12335
|
+
* dislike), `--cont-batching`, `--rope-scaling`, …
|
|
12336
|
+
*
|
|
12337
|
+
* It is NOT a second place to set the flags above. A token that collides
|
|
12338
|
+
* with a typed field is REJECTED at start, naming the field that owns it
|
|
12339
|
+
* (`assertNoOwnedFlags`), because two knobs writing the same argv is exactly
|
|
12340
|
+
* the "two switches that disagree" failure this repo has already shipped
|
|
12341
|
+
* twice (D62).
|
|
12342
|
+
*/
|
|
12343
|
+
extraArgs: array(string()).default([]),
|
|
12316
12344
|
/** Else lazy: first generate boots it. */
|
|
12317
12345
|
autoStart: boolean().default(false),
|
|
12318
12346
|
/** 0 = never; frees RAM after quiet periods. */
|
|
12319
12347
|
idleStopMinutes: number().int().default(30)
|
|
12320
12348
|
});
|
|
12349
|
+
/**
|
|
12350
|
+
* Where a multi-GB install currently is. A single 0..1 fraction cannot answer
|
|
12351
|
+
* "is it stuck?" for an install that is three files (shards + mmproj) followed
|
|
12352
|
+
* by a sha256 pass over 22 GB — during which the fraction sat at 1.0 and the
|
|
12353
|
+
* node looked hung. Phase + file + bytes is the smallest shape that does.
|
|
12354
|
+
*/
|
|
12355
|
+
var LlmDownloadProgressSchema = object({
|
|
12356
|
+
phase: _enum(["downloading", "verifying"]),
|
|
12357
|
+
/** The artifact currently moving, e.g. `mmproj-F16.gguf`. */
|
|
12358
|
+
file: string(),
|
|
12359
|
+
fileIndex: number().int(),
|
|
12360
|
+
fileCount: number().int(),
|
|
12361
|
+
/** Across the WHOLE install, not the current file. */
|
|
12362
|
+
downloadedBytes: number(),
|
|
12363
|
+
totalBytes: number().optional()
|
|
12364
|
+
});
|
|
12321
12365
|
var LlmRuntimeStatusSchema = object({
|
|
12322
12366
|
/** Status is ALWAYS node-qualified. */
|
|
12323
12367
|
nodeId: string(),
|
|
@@ -12334,6 +12378,8 @@ var LlmRuntimeStatusSchema = object({
|
|
|
12334
12378
|
modelPath: string().optional(),
|
|
12335
12379
|
modelId: string().optional(),
|
|
12336
12380
|
downloadProgress: number().min(0).max(1).optional(),
|
|
12381
|
+
/** Detail behind `downloadProgress`; present for the same lifetime. */
|
|
12382
|
+
download: LlmDownloadProgressSchema.optional(),
|
|
12337
12383
|
lastError: string().optional(),
|
|
12338
12384
|
crashesInWindow: number(),
|
|
12339
12385
|
/** Child RSS (sampled best-effort). */
|
|
@@ -12344,7 +12390,14 @@ var LlmNodeModelSchema = object({
|
|
|
12344
12390
|
file: string(),
|
|
12345
12391
|
sizeBytes: number(),
|
|
12346
12392
|
catalogId: string().optional(),
|
|
12347
|
-
installedAt: number().optional()
|
|
12393
|
+
installedAt: number().optional(),
|
|
12394
|
+
/**
|
|
12395
|
+
* Absolute path on the node. Present so a file that is on disk but matches
|
|
12396
|
+
* no catalog entry — a custom Hugging Face install, or a GGUF the operator
|
|
12397
|
+
* copied in by hand — is still SELECTABLE, as a `{kind:'path'}` ref. Without
|
|
12398
|
+
* it the picker could list such a file and do nothing with it.
|
|
12399
|
+
*/
|
|
12400
|
+
path: string().optional()
|
|
12348
12401
|
});
|
|
12349
12402
|
var LlmRuntimeDiskUsageSchema = object({
|
|
12350
12403
|
nodeId: string(),
|
|
@@ -12422,9 +12475,12 @@ var LlmProfileSchema = object({
|
|
|
12422
12475
|
systemPrompt: string().optional(),
|
|
12423
12476
|
/** Total generation bound — the only one a unary call has. */
|
|
12424
12477
|
timeoutMs: number().int().positive().default(6e4),
|
|
12425
|
-
/**
|
|
12478
|
+
/** The TCP handshake only — "is the port even open". NOT the wait for
|
|
12479
|
+
* response headers: on the LM Studio / llama-server wire those are written
|
|
12480
|
+
* once the model has finished loading, so they belong to the bound below. */
|
|
12426
12481
|
connectTimeoutMs: number().int().positive().default(1e4),
|
|
12427
|
-
/** Accepted, but no output yet —
|
|
12482
|
+
/** Accepted, but no output yet — response headers included, because a cold
|
|
12483
|
+
* GPU load is exactly what happens before them. */
|
|
12428
12484
|
firstTokenTimeoutMs: number().int().positive().default(12e4),
|
|
12429
12485
|
/** Output started then stopped. */
|
|
12430
12486
|
idleTimeoutMs: number().int().positive().default(6e4),
|
|
@@ -12487,6 +12543,36 @@ var ManagedModelCatalogEntrySchema = object({
|
|
|
12487
12543
|
/** Vision models: companion projector file. */
|
|
12488
12544
|
mmprojUrl: string().optional()
|
|
12489
12545
|
});
|
|
12546
|
+
/**
|
|
12547
|
+
* The outcome of turning one operator-typed Hugging Face reference into a
|
|
12548
|
+
* download plan. A RESULT, never a throw: "this repo has 24 quantizations and
|
|
12549
|
+
* I will not pick for you" is a normal answer the UI has to render, not an
|
|
12550
|
+
* exception.
|
|
12551
|
+
*
|
|
12552
|
+
* `candidates` is the whole reason the refusal is usable — every string in it
|
|
12553
|
+
* is a tag that resolves when pasted back as `<org>/<repo>:<TAG>`.
|
|
12554
|
+
*/
|
|
12555
|
+
var HfModelResolutionSchema = discriminatedUnion("ok", [object({
|
|
12556
|
+
ok: literal(true),
|
|
12557
|
+
/** Ready to hand to `installModel` unchanged. */
|
|
12558
|
+
model: ManagedModelRefSchema,
|
|
12559
|
+
label: string(),
|
|
12560
|
+
repo: string(),
|
|
12561
|
+
quantization: string(),
|
|
12562
|
+
purpose: _enum(["text", "vision"]),
|
|
12563
|
+
totalBytes: number(),
|
|
12564
|
+
/** mmproj + shards, for the preview: an operator approving 23 GB should
|
|
12565
|
+
* see that 0.9 GB of it is a projector they did not name. */
|
|
12566
|
+
extraFilenames: array(string())
|
|
12567
|
+
}), object({
|
|
12568
|
+
ok: literal(false),
|
|
12569
|
+
code: string(),
|
|
12570
|
+
message: string(),
|
|
12571
|
+
candidates: array(string()).optional(),
|
|
12572
|
+
/** Set when the refusal was only the ceiling: re-calling with
|
|
12573
|
+
* `maxBytes: requiredBytes` is the operator's explicit override. */
|
|
12574
|
+
requiredBytes: number().optional()
|
|
12575
|
+
})]);
|
|
12490
12576
|
var LlmRuntimeNodeSchema = object({
|
|
12491
12577
|
nodeId: string(),
|
|
12492
12578
|
reachable: boolean(),
|
|
@@ -12523,6 +12609,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
|
|
|
12523
12609
|
consumer: string().optional(),
|
|
12524
12610
|
profileId: string().optional()
|
|
12525
12611
|
}), array(LlmUsageRollupSchema)), method(object({}), array(ManagedModelCatalogEntrySchema)), method(object({}), array(LlmRuntimeNodeSchema)), method(object({ nodeId: string() }), array(LlmNodeModelSchema)), method(object({
|
|
12612
|
+
/** `https://huggingface.co/<org>/<repo>/resolve/main/<f>.gguf`,
|
|
12613
|
+
* `<org>/<repo>/<f>.gguf`, `<org>/<repo>` or `<org>/<repo>:<QUANT>`. */
|
|
12614
|
+
ref: string(),
|
|
12615
|
+
/** Explicit ceiling override, in bytes. Absent = the built-in ceiling. */
|
|
12616
|
+
maxBytes: number().positive().optional()
|
|
12617
|
+
}), HfModelResolutionSchema, {
|
|
12618
|
+
kind: "mutation",
|
|
12619
|
+
auth: "admin"
|
|
12620
|
+
}), method(object({
|
|
12526
12621
|
nodeId: string(),
|
|
12527
12622
|
model: ManagedModelRefSchema
|
|
12528
12623
|
}), _void(), {
|
|
@@ -17655,6 +17750,17 @@ var maxSessionHoldMsField = {
|
|
|
17655
17750
|
default: 12e4,
|
|
17656
17751
|
step: 5e3
|
|
17657
17752
|
};
|
|
17753
|
+
/**
|
|
17754
|
+
* Quiet period that closes an `audioMode: 'on-motion'` audio window. Floor of
|
|
17755
|
+
* 5s so a rearm can never degenerate into per-event stream churn; default 90s
|
|
17756
|
+
* comfortably outlives the gap between two PIR wakes on a battery camera.
|
|
17757
|
+
*/
|
|
17758
|
+
var audioMotionWindowMsField = {
|
|
17759
|
+
min: 5e3,
|
|
17760
|
+
max: 6e5,
|
|
17761
|
+
default: 9e4,
|
|
17762
|
+
step: 5e3
|
|
17763
|
+
};
|
|
17658
17764
|
var motionFpsField = {
|
|
17659
17765
|
min: 1,
|
|
17660
17766
|
max: 30,
|
|
@@ -17831,6 +17937,27 @@ var RunnerCameraConfigSchema = object({
|
|
|
17831
17937
|
* resolved `CameraDetectionConfig`.
|
|
17832
17938
|
*/
|
|
17833
17939
|
maxSessionHoldMs: number().min(maxSessionHoldMsField.min).max(maxSessionHoldMsField.max).optional(),
|
|
17940
|
+
/**
|
|
17941
|
+
* Orchestrator-side quiet period (ms) that closes an `audioMode:
|
|
17942
|
+
* 'on-motion'` audio window, measured from the LAST motion event.
|
|
17943
|
+
*
|
|
17944
|
+
* This exists because the falling edge cannot be relied on. Camera-native
|
|
17945
|
+
* providers emit motion as a RISING EDGE ONLY (Reolink's Baichuan push and
|
|
17946
|
+
* its email-push SMTP path both emit `detected: true` and never the
|
|
17947
|
+
* counterpart); only the frame-diff analyzer emits falls. So on an
|
|
17948
|
+
* onboard-only camera a window that closed only on `detected: false` never
|
|
17949
|
+
* closed at all, and `on-motion` silently behaved as `always-on` — on a
|
|
17950
|
+
* battery camera, the one failure mode the mode exists to prevent.
|
|
17951
|
+
*
|
|
17952
|
+
* Every motion event rearms this timer WITHOUT restarting the stream, so a
|
|
17953
|
+
* burst of re-fires costs nothing. A falling edge, when one does arrive,
|
|
17954
|
+
* still closes earlier via `motionCooldownMs` — whichever comes first wins.
|
|
17955
|
+
*
|
|
17956
|
+
* Not consumed by the runner: carried here so it shares the per-camera
|
|
17957
|
+
* device-settings surface with `motionCooldownMs`, exactly like
|
|
17958
|
+
* `maxSessionHoldMs`.
|
|
17959
|
+
*/
|
|
17960
|
+
audioMotionWindowMs: number().min(audioMotionWindowMsField.min).max(audioMotionWindowMsField.max).optional(),
|
|
17834
17961
|
motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
|
|
17835
17962
|
detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
|
|
17836
17963
|
motionStreamId: string(),
|
|
@@ -17926,7 +18053,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
17926
18053
|
*/
|
|
17927
18054
|
inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
|
|
17928
18055
|
});
|
|
17929
|
-
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;
|
|
18056
|
+
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;
|
|
17930
18057
|
/**
|
|
17931
18058
|
* Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
|
|
17932
18059
|
* load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
|
|
@@ -24332,6 +24459,33 @@ method(object({
|
|
|
24332
24459
|
* as `unknown`, never guessed. A day reference scored against an IR frame
|
|
24333
24460
|
* collapses the cosine and would latch a false alarm every single night. */
|
|
24334
24461
|
var SceneConditionSchema = string();
|
|
24462
|
+
/**
|
|
24463
|
+
* What a scene does when the CURRENT light has no reference of its own.
|
|
24464
|
+
*
|
|
24465
|
+
* The lighting variants are not equally likely to exist. Almost every operator
|
|
24466
|
+
* captures daylight and then never stands outside at 22:00 to capture IR, and a
|
|
24467
|
+
* scene that is only ever going to be asked about a daytime question ("is the
|
|
24468
|
+
* bin still on the kerb at 08:00") does not need a night reference at all. The
|
|
24469
|
+
* night half must therefore be OPTIONAL, and optional means the scene keeps
|
|
24470
|
+
* working without it rather than degrading into a permanent complaint.
|
|
24471
|
+
*
|
|
24472
|
+
* - `skip` (default) — the check in that light is not made. Not a verdict, not
|
|
24473
|
+
* an alarm, not even an `unknown`: the live state simply stays whatever the
|
|
24474
|
+
* last covered light left it at, the latch is untouched, and the hysteresis
|
|
24475
|
+
* run is neither spent nor cleared. The scene resumes by itself at first
|
|
24476
|
+
* light. This is the only behaviour under which "I never captured IR" is a
|
|
24477
|
+
* configuration choice instead of a nightly fault.
|
|
24478
|
+
* - `judge-anyway` — score against the OTHER conditions' references. Available
|
|
24479
|
+
* for cameras whose IR frame is close enough to daylight (a floodlit
|
|
24480
|
+
* driveway, an always-white-light doorbell), and wrong for everything else:
|
|
24481
|
+
* cross-condition cosines are not comparable, so a day reference against a
|
|
24482
|
+
* true IR frame collapses and the scene reports a theft at 21:40.
|
|
24483
|
+
*
|
|
24484
|
+
* Never applies when the scene has NO comparable reference at all — that is
|
|
24485
|
+
* "not armed yet", it is reported as `no-reference-for-condition`, and silence
|
|
24486
|
+
* there would hide a scene the operator never finished setting up.
|
|
24487
|
+
*/
|
|
24488
|
+
var SceneUncoveredPolicySchema = _enum(["skip", "judge-anyway"]);
|
|
24335
24489
|
/** `matched` = the baseline is what we see; `diverged` = it demonstrably is not;
|
|
24336
24490
|
* `unknown` = we cannot judge (no reference for this condition, encoder model
|
|
24337
24491
|
* changed, view shifted, no snapshot). `unknown` is a real value, not a null,
|
|
@@ -24387,6 +24541,9 @@ var SceneCheckSchema = discriminatedUnion("mode", [object({
|
|
|
24387
24541
|
hysteresisCount: number().int().positive()
|
|
24388
24542
|
})]);
|
|
24389
24543
|
var SCENE_DEFAULT_ANCHOR_THRESHOLD = .85;
|
|
24544
|
+
/** Night is OPTIONAL. A scene with only a daylight reference sits the IR hours
|
|
24545
|
+
* out in silence rather than reporting a fault every night. */
|
|
24546
|
+
var SCENE_DEFAULT_UNCOVERED_POLICY = "skip";
|
|
24390
24547
|
/**
|
|
24391
24548
|
* Vision-model adjudication of a candidate flip. Field names deliberately
|
|
24392
24549
|
* mirror `NcConfirmSchema` so an operator meets one vocabulary, not two.
|
|
@@ -24453,6 +24610,21 @@ var SceneMonitorSchema = object({
|
|
|
24453
24610
|
* automation can react to the bin coming back without the operator's own
|
|
24454
24611
|
* alarm silently clearing itself. */
|
|
24455
24612
|
autoRestore: boolean().default(false),
|
|
24613
|
+
/** What to do when the current light has no reference of its own. See
|
|
24614
|
+
* {@link SceneUncoveredPolicySchema} — the default makes night OPTIONAL. */
|
|
24615
|
+
onUncoveredCondition: SceneUncoveredPolicySchema.default(SCENE_DEFAULT_UNCOVERED_POLICY),
|
|
24616
|
+
/**
|
|
24617
|
+
* The light whose checks are currently being SAT OUT under
|
|
24618
|
+
* `onUncoveredCondition: 'skip'` — `null` when the scene is checking normally.
|
|
24619
|
+
*
|
|
24620
|
+
* Engine-reported and advisory only: it moves no verdict, no latch and no
|
|
24621
|
+
* hysteresis. It exists so the card can say *"night (IR) — checks paused,
|
|
24622
|
+
* nothing captured in this light"* in the same calm voice as the coverage
|
|
24623
|
+
* line, because the alternative is a scene that silently stops answering
|
|
24624
|
+
* after sunset with nothing anywhere saying why. A skipped check must never
|
|
24625
|
+
* read as a broken one.
|
|
24626
|
+
*/
|
|
24627
|
+
suspendedCondition: SceneConditionSchema.nullable().default(null),
|
|
24456
24628
|
/** Named cause when `verdict === 'unknown'`. */
|
|
24457
24629
|
unavailable: SceneUnavailableSchema.nullable(),
|
|
24458
24630
|
/** Conditions that have at least one comparable reference — the coverage line
|
|
@@ -24496,6 +24668,7 @@ DeviceType.Camera, method(object({ deviceId: number() }), SceneMonitorStatusSche
|
|
|
24496
24668
|
minObservationSpacingSec: number().int().min(0).max(3600).optional(),
|
|
24497
24669
|
anchorThreshold: number().min(0).max(1).optional(),
|
|
24498
24670
|
autoRestore: boolean().optional(),
|
|
24671
|
+
onUncoveredCondition: SceneUncoveredPolicySchema.optional(),
|
|
24499
24672
|
/** `null` clears the vision-model adjudicator. */
|
|
24500
24673
|
confirm: SceneConfirmSchema.nullable().optional()
|
|
24501
24674
|
})
|
|
@@ -27727,6 +27900,12 @@ Object.freeze({
|
|
|
27727
27900
|
addonId: null,
|
|
27728
27901
|
access: "view"
|
|
27729
27902
|
},
|
|
27903
|
+
"llm.resolveModelRef": {
|
|
27904
|
+
capName: "llm",
|
|
27905
|
+
capScope: "system",
|
|
27906
|
+
addonId: null,
|
|
27907
|
+
access: "create"
|
|
27908
|
+
},
|
|
27730
27909
|
"llm.setDefault": {
|
|
27731
27910
|
capName: "llm",
|
|
27732
27911
|
capScope: "system",
|
|
@@ -33282,7 +33461,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
33282
33461
|
capability: adminUiCapability,
|
|
33283
33462
|
provider: {
|
|
33284
33463
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
33285
|
-
getVersion: async () => ({ version: "1.2.
|
|
33464
|
+
getVersion: async () => ({ version: "1.2.63" })
|
|
33286
33465
|
}
|
|
33287
33466
|
}];
|
|
33288
33467
|
}
|
package/package.json
CHANGED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{I as e,K as t,Q as n,S as r,W as i,a,b as o,q as s,t as c,x as l,z as u}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{Z as d,o as f}from"./player-overlays-7AKPeTm-.js";import{At as p,Dt as m,Et as h,Ft as g,It as _,Kt as v,Lt as y,Mt as b,Pt as x,Rt as S,Tt as C,Xt as w,h as T,jt as E,kt as D,nt as O,tt as k}from"./src-CgOOvCVA.js";import{K as A}from"./src-BaVKQIP9.js";import{t as j}from"./boxes-BN_wTQoj.js";import{n as M,t as N}from"./send-CiGeFhM_.js";import{t as P}from"./pencil-CZ2gMyTB.js";import{t as F}from"./plus-ChsVL8uT.js";import{t as I}from"./server-BBJTl0ih.js";import{t as L}from"./square-BlgtgcV9.js";import{C as R,D as z,H as B,K as V,N as H,V as U,i as ee,l as W,s as te,t as G,v as ne}from"./index-Dr-ap6SH.js";import{t as K}from"./AdminPage-CCD07UMs.js";import{t as re}from"./AdminTabs-D4DXIa-o.js";var q=V(`cloud`,[[`path`,{d:`M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z`,key:`p7xjir`}]]);n();var J=[`llm`,`listProfiles`],ie=[`llm`,`listProfileKinds`],ae=[`llm`,`getDefaults`],oe=[`llm`,`listRuntimeNodes`],se=[`llm`,`listModelCatalog`],ce=[`llm`,`getUsage`],le=[{purpose:`vision`,visionOnly:!0},{purpose:`text`,visionOnly:!1}],ue=new Map(Object.entries({openai:q,anthropic:q,google:q,"openai-compatible":ne,"managed-local":H}));function de(e){return ue.get(e)??null}function Y(e){return typeof e==`string`&&e.length>0?e:void 0}function X(e){if(typeof e==`number`&&Number.isFinite(e))return e;if(typeof e==`string`&&e.trim()!==``){let t=Number(e);return Number.isFinite(t)?t:void 0}}function Z(e){return e===!0}function fe(e){return{model:e.model,baseUrl:e.baseUrl,apiKey:e.apiKey,supportsVision:e.supportsVision,temperature:e.temperature,topP:e.topP,topK:e.topK,maxTokens:e.maxTokens,contextLength:e.contextLength,systemPrompt:e.systemPrompt,timeoutMs:e.timeoutMs,connectTimeoutMs:e.connectTimeoutMs,firstTokenTimeoutMs:e.firstTokenTimeoutMs,idleTimeoutMs:e.idleTimeoutMs,retryEnabled:e.retry.enabled,retryMaxAttempts:e.retry.maxAttempts,toolsEnabled:e.toolsEnabled,contextSize:e.runtime?.contextSize,gpuLayers:e.runtime?.gpuLayers,threads:e.runtime?.threads,parallel:e.runtime?.parallel,idleStopMinutes:e.runtime?.idleStopMinutes,batchSize:e.runtime?.batchSize,ubatchSize:e.runtime?.ubatchSize,flashAttention:e.runtime?.flashAttention,mlock:e.runtime?.mlock,noMmap:e.runtime?.noMmap,cacheTypeK:e.runtime?.cacheTypeK,cacheTypeV:e.runtime?.cacheTypeV}}var pe=[`f32`,`f16`,`q8_0`,`q5_1`,`q5_0`,`q4_1`,`q4_0`];function me(e){return typeof e==`string`&&pe.includes(e)?e:void 0}function he(e,t,n){let r=X(e.threads),i=X(e.batchSize),a=X(e.ubatchSize),o=me(e.cacheTypeK),s=me(e.cacheTypeV);return{nodeId:t,engine:`llama-cpp`,model:{kind:`catalog`,catalogId:n},contextSize:X(e.contextSize)??4096,gpuLayers:X(e.gpuLayers)??0,...r===void 0?{}:{threads:r},parallel:X(e.parallel)??1,...i===void 0?{}:{batchSize:i},...a===void 0?{}:{ubatchSize:a},flashAttention:Z(e.flashAttention),mlock:Z(e.mlock),noMmap:Z(e.noMmap),...o===void 0?{}:{cacheTypeK:o},...s===void 0?{}:{cacheTypeV:s},autoStart:Z(e.autoStart),idleStopMinutes:X(e.idleStopMinutes)??30}}function ge(e,t,n,r,i){let a={id:n?.id??crypto.randomUUID(),name:t,kind:e,addonId:`ai`,enabled:n?.enabled??!0,model:Y(r.model)??n?.model??``,supportsVision:i?.supportsVision??Z(r.supportsVision),timeoutMs:X(r.timeoutMs)??A.totalMs,connectTimeoutMs:X(r.connectTimeoutMs)??A.connectMs,firstTokenTimeoutMs:X(r.firstTokenTimeoutMs)??A.firstTokenMs,idleTimeoutMs:X(r.idleTimeoutMs)??A.idleMs,retry:{enabled:Z(r.retryEnabled),maxAttempts:X(r.retryMaxAttempts)??1},toolsEnabled:Z(r.toolsEnabled)},o=Y(r.baseUrl),s=Y(r.apiKey),c=X(r.temperature),l=X(r.topP),u=X(r.topK),d=X(r.maxTokens),f=X(r.contextLength),p=Y(r.systemPrompt);return{...a,...o===void 0?{}:{baseUrl:o},...s===void 0?{}:{apiKey:s},...c===void 0?{}:{temperature:c},...l===void 0?{}:{topP:l},...u===void 0?{}:{topK:u},...d===void 0?{}:{maxTokens:d},...f===void 0?{}:{contextLength:f},...p===void 0?{}:{systemPrompt:p},...i===void 0?{}:{model:i.catalogId,runtime:he(r,i.nodeId,i.catalogId)}}}function _e(e){let t=new Map;for(let n of e){let e=t.get(n.addonId)??[];e.push(n),t.set(n.addonId,e)}return[...t.entries()].map(([e,t])=>({addonId:e,kinds:t}))}function Q({kind:e,className:t}){let n=de(e.kind);return n===null?l(`span`,{className:t,children:e.icon}):l(n,{className:t})}function ve({kinds:e,onPick:t,onCancel:n}){let{t:a}=G(),o=i(()=>_e(e),[e]);return l(C,{open:!0,onOpenChange:e=>!e&&n(),children:r(m,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(p,{children:l(E,{children:a(`ai.chooseKind`,`Choose a profile type`)})}),r(h,{className:`space-y-4 pr-1`,children:[o.length===0&&l(`p`,{className:`text-xs text-foreground-subtle`,children:a(`ai.noKinds`,`No AI provider is installed.`)}),o.map(e=>r(`div`,{children:[l(`div`,{className:`mb-1.5 text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:e.addonId}),l(`div`,{className:`grid grid-cols-2 gap-2 sm:grid-cols-3`,children:e.kinds.map(n=>r(`button`,{type:`button`,onClick:()=>t(n),className:`flex flex-col items-center gap-1.5 rounded-lg border border-border bg-surface px-3 py-3 text-xs transition-colors hover:border-primary/50 hover:bg-surface-hover`,children:[l(Q,{kind:n,className:`h-5 w-5 text-foreground-subtle`}),l(`span`,{className:`font-medium text-foreground`,children:n.label})]},`${e.addonId}:${n.kind}`))})]},e.addonId))]}),l(D,{children:l(S,{size:`sm`,variant:`secondary`,type:`button`,onClick:n,children:a(`common.cancel`,`Cancel`)})})]})})}function ye({kind:e,existing:t,onSave:n,onCancel:c,saving:u,error:f}){let{t:_}=G(),b=d(),w=e.kind===`managed-local`,[O,k]=s(t?.name??e.label),[A,j]=s(()=>t===null?{}:fe(t)),[M,N]=s(t?.runtime?.nodeId??`hub`),[P,F]=s(t?.runtime?.model.kind===`catalog`?t.runtime.model.catalogId:``),I=a({queryKey:se,enabled:w,queryFn:()=>b.trpcClient.llm.listModelCatalog.query({})}),L=i(()=>[{value:``,label:_(`ai.selectModel`,`Select a model…`)},...(I.data??[]).map(e=>({value:e.id,label:`${e.label} · ${e.quantization} · ${(e.sizeBytes/1e9).toFixed(1)} GB`}))],[I.data,_]),z=()=>{if(!w){n(ge(e.kind,O,t,A));return}let r=I.data?.find(e=>e.id===P);n(ge(e.kind,O,t,A,{nodeId:M,catalogId:P,supportsVision:r?.purpose===`vision`}))},B=u||O.trim()===``||w&&P===``;return l(C,{open:!0,onOpenChange:e=>!e&&c(),children:r(m,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(p,{children:r(E,{className:`flex items-center gap-2`,children:[l(Q,{kind:e,className:`h-4 w-4 text-foreground-subtle`}),t===null?_(`ai.newProfile`,`New {{kind}} profile`,{kind:e.label}):_(`ai.editProfile`,`Edit {{name}}`,{name:t.name})]})}),r(h,{className:`space-y-3 pr-1`,children:[f!==null&&l(`div`,{className:`rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-xs text-danger`,children:f}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-profile-name`,children:_(`ai.name`,`Name`)}),l(g,{id:`ai-profile-name`,value:O,onChange:e=>k(e.target.value),placeholder:e.label})]}),w&&r(o,{children:[l(T,{selectedNodeId:M,onSelect:N,label:_(`ai.runtimeNode`,`Runtime node`),alwaysShow:!0}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-profile-catalog`,children:_(`ai.model`,`Model`)}),l(x,{id:`ai-profile-catalog`,value:P,options:L,onChange:e=>F(e.target.value)})]})]}),l(v,{schema:e.configSchema,values:A,onChange:j}),t!==null&&l(`p`,{className:`text-[10px] text-foreground-subtle`,children:_(`ai.secretHint`,`A stored API key is never shown. Leave it as-is to keep it; type a new value to replace it.`)})]}),r(D,{children:[w&&P===``&&l(y,{variant:`warning`,children:_(`ai.pickModelFirst`,`pick a model`)}),l(S,{size:`sm`,variant:`secondary`,type:`button`,onClick:c,children:_(`common.cancel`,`Cancel`)}),r(S,{size:`sm`,type:`button`,disabled:B,onClick:z,children:[u&&l(R,{className:`h-3.5 w-3.5 animate-spin`}),t===null?_(`ai.createProfile`,`Create profile`):_(`ai.saveChanges`,`Save changes`)]})]})]})})}n();function be(e){return[{key:`name`,header:e.t(`ai.colProfile`,`Profile`),render:t=>{let n=e.kindByName.get(t.kind);return r(`span`,{className:`flex items-center gap-2`,children:[l(`span`,{className:`flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-surface`,title:n?.label??t.kind,children:n===void 0?l(`span`,{className:`text-xs text-foreground-subtle`,children:`?`}):l(Q,{kind:n,className:`h-4 w-4 text-foreground-subtle`})}),r(`span`,{className:`min-w-0`,children:[l(`span`,{className:`block truncate text-sm font-medium text-foreground`,children:t.name}),e.testResult?.id===t.id&&l(`span`,{className:`block truncate text-[10px] ${e.testResult.ok?`text-success`:`text-danger`}`,children:e.testResult.text})]})]})}},{key:`kind`,header:e.t(`ai.colKind`,`Kind`),nowrap:!0,render:t=>l(`span`,{className:`text-[11px] text-foreground-subtle`,children:e.kindByName.get(t.kind)?.label??t.kind})},{key:`model`,header:e.t(`ai.colModel`,`Model`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.model})},{key:`vision`,header:e.t(`ai.colVision`,`Vision`),align:`center`,nowrap:!0,render:t=>t.supportsVision?l(y,{variant:`info`,style:`outline`,children:e.t(`ai.vision`,`vision`)}):l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`})},{key:`node`,header:e.t(`ai.colNode`,`Node`),nowrap:!0,render:e=>e.runtime===void 0?l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`}):l(y,{variant:`default`,children:e.runtime.nodeId})},{key:`enabled`,header:e.t(`ai.colOn`,`On`),align:`center`,nowrap:!0,render:t=>l(b,{checked:t.enabled,onCheckedChange:()=>e.onToggle(t),"aria-label":`toggle ${t.name}`})},{key:`actions`,header:``,align:`right`,nowrap:!0,render:t=>r(`span`,{className:`flex items-center justify-end gap-1`,children:[l(S,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onTest(t),title:e.t(`ai.test`,`Test`),children:e.testingId===t.id?l(R,{className:`h-3.5 w-3.5 animate-spin`}):l(N,{className:`h-3.5 w-3.5`})}),l(S,{size:`sm`,variant:`ghost`,type:`button`,disabled:!e.kindByName.has(t.kind),onClick:()=>e.onEdit(t),title:e.t(`common.edit`,`Edit`),children:l(P,{className:`h-3.5 w-3.5`})}),l(S,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onDelete(t),title:e.t(`common.delete`,`Delete`),children:l(te,{className:`h-3.5 w-3.5 text-danger`})})]})}]}function xe(){let{t:e}=G(),t=d(),[n,o]=s({mode:`closed`}),[u,f]=s(null),[p,m]=s(null),h=a({queryKey:J,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),g=a({queryKey:ie,queryFn:async()=>(await t.trpcClient.llm.listProfileKinds.query({})).map(e=>({...e,configSchema:e.configSchema}))}),v=()=>{h.refetch()},y=c({mutationFn:e=>t.trpcClient.llm.upsertProfile.mutate({profile:e}),onSuccess:()=>{o({mode:`closed`}),m(null),v()},onError:t=>m(t instanceof Error?t.message:e(`ai.saveFailed`,`Save failed`))}),b=c({mutationFn:e=>t.trpcClient.llm.deleteProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:v}),x=c({mutationFn:e=>t.trpcClient.llm.testProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:(e,t)=>f({id:t.id,ok:e.ok,text:e.ok?`${e.text} (${String(e.usage.outputTokens)} tok, ${String(e.latencyMs)}ms)`:`${e.code}: ${e.message}`})}),C=h.data??[],T=i(()=>g.data??[],[g.data]),E=i(()=>{let e=new Map;for(let t of T)e.set(t.kind,t);return e},[T]);return r(K,{icon:W,title:e(`ai.profilesTitle`,`AI profiles`),subtitle:e(`ai.profilesSubtitle`,`One row = one usable model endpoint. The defaults below decide who answers when a feature names no profile.`),actions:r(S,{size:`sm`,type:`button`,onClick:()=>{m(null),o({mode:`pick-kind`})},children:[l(F,{className:`h-3.5 w-3.5`}),e(`ai.addProfile`,`Add profile`)]}),children:[h.isError&&l(w,{title:e(`ai.loadFailed`,`Failed to load profiles`),message:h.error instanceof Error?h.error.message:e(`common.error`,`Error`),onRetry:()=>void h.refetch()}),l(Se,{profiles:C}),h.isLoading&&l(`div`,{className:`flex items-center justify-center py-16`,children:l(R,{className:`h-6 w-6 animate-spin text-primary`})}),!h.isLoading&&C.length===0&&l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noProfiles`,`No AI profiles yet. Click "Add profile" to configure one.`)}),C.length>0&&l(_,{children:l(k,{columns:be({kindByName:E,testResult:u,testingId:x.isPending?x.variables?.id??null:null,t:e,onToggle:e=>y.mutate({...e,enabled:!e.enabled,apiKey:`__redacted__`}),onTest:e=>x.mutate(e),onEdit:e=>{let t=E.get(e.kind);t!==void 0&&(m(null),o({mode:`form`,kind:t,profile:e}))},onDelete:e=>b.mutate(e)}),rows:C,rowKey:e=>e.id,minWidthPx:760,bordered:!1,mobileMode:`scroll`,maxBodyHeight:`max-h-[60vh]`})}),n.mode===`pick-kind`&&l(ve,{kinds:T,onCancel:()=>o({mode:`closed`}),onPick:e=>o({mode:`form`,kind:e,profile:null})}),n.mode===`form`&&l(ye,{kind:n.kind,existing:n.profile,saving:y.isPending,error:p,onSave:e=>y.mutate(e),onCancel:()=>o({mode:`closed`})})]})}function Se({profiles:e}){let{t}=G(),n=d(),i=a({queryKey:ae,queryFn:()=>n.trpcClient.llm.getDefaults.query({})}),o=c({mutationFn:e=>n.trpcClient.llm.setDefault.mutate({selector:{purpose:e.purpose},profileId:e.profileId}),onSuccess:()=>{i.refetch()}}),s=e=>(i.data??[]).find(t=>`purpose`in t.selector&&t.selector.purpose===e)?.profileId??``,u=e=>e===`vision`?t(`ai.defaultVision`,`Default vision profile`):t(`ai.defaultText`,`Default text profile`);return l(_,{children:l(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:le.map(({purpose:n,visionOnly:i})=>{let a=i?e.filter(e=>e.supportsVision):e,c=s(n),d=e.find(e=>e.id===c);return r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`llm-default-${n}`,children:u(n)}),r(`select`,{id:`llm-default-${n}`,"aria-label":u(n),className:`h-7 w-full rounded-md border border-border bg-surface px-2.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary`,value:c,onChange:e=>o.mutate({purpose:n,profileId:e.target.value===``?null:e.target.value}),children:[l(`option`,{value:``,children:t(`ai.none`,`None`)}),c!==``&&!a.some(e=>e.id===c)&&l(`option`,{value:c,children:d?.name??c}),a.map(e=>r(`option`,{value:e.id,children:[e.name,` · `,e.model]},e.id))]}),c!==``&&d===void 0&&l(`p`,{className:`mt-1 text-[10px] text-danger`,children:t(`ai.defaultMissing`,`This default names a profile that no longer exists.`)}),d!==void 0&&!d.enabled&&l(`p`,{className:`mt-1 text-[10px] text-warning`,children:t(`ai.defaultDisabled`,`This default profile is disabled — callers resolve to no profile.`)}),o.error!=null&&l(`p`,{className:`mt-1 text-[10px] text-danger`,children:String(o.error)})]},n)})})})}n();var Ce=5e3;function we(e){return`${(e/1e9).toFixed(1)} GB`}function Te(){let{t:e}=G(),t=d(),n=a({queryKey:oe,refetchInterval:Ce,queryFn:()=>t.trpcClient.llm.listRuntimeNodes.query({})}),o=i(()=>[{key:`node`,header:e(`ai.colNode`,`Node`),render:e=>l(`span`,{className:`text-sm font-medium text-foreground`,children:e.nodeId})},{key:`state`,header:e(`ai.colState`,`State`),nowrap:!0,render:t=>r(`span`,{className:`flex items-center gap-1.5`,children:[l(y,{variant:t.reachable?`success`:`danger`,children:t.reachable?t.status?.state??e(`ai.ready`,`ready`):e(`ai.unreachable`,`unreachable`)}),t.status?.downloadProgress!==void 0&&l(y,{variant:`info`,children:`${String(Math.round(t.status.downloadProgress*100))}%`})]})},{key:`model`,header:e(`ai.colModel`,`Model`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.status?.modelId??`—`})},{key:`disk`,header:e(`ai.colDisk`,`On disk`),align:`right`,nowrap:!0,render:e=>l(`span`,{className:`text-[11px] text-foreground-subtle`,children:e.disk===void 0?`—`:we(e.disk.modelsBytes)})},{key:`error`,header:e(`ai.colError`,`Error`),render:e=>e.error===void 0?l(`span`,{className:`text-[11px] text-foreground-subtle`,children:`—`}):l(`span`,{className:`text-[11px] text-danger`,children:e.error})}],[e]),s=n.data??[];return r(K,{icon:I,title:e(`ai.runtimesTitle`,`Managed runtimes`),subtitle:e(`ai.runtimesSubtitle`,`Nodes advertising the llm-runtime capability: what each has loaded, what it is downloading, and how much model data sits on its disk.`),children:[n.isError&&l(w,{title:e(`ai.runtimesFailed`,`Failed to read runtime nodes`),message:n.error instanceof Error?n.error.message:e(`common.error`,`Error`),onRetry:()=>void n.refetch()}),s.length===0?l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noRuntimes`,`No node advertises the llm-runtime capability.`)}):l(_,{children:l(k,{columns:o,rows:s,rowKey:e=>e.nodeId,minWidthPx:640,bordered:!1,mobileMode:`scroll`,maxBodyHeight:O})})]})}var Ee=`/addon/ai/test-chat`;function De(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Oe(e){if(!De(e))return null;let t=e.kind;return t!==`snapshot`&&t!==`track`||typeof e.mimeType!=`string`||typeof e.sizeBytes!=`number`?null:{kind:t,mimeType:e.mimeType,sizeBytes:e.sizeBytes,...typeof e.mediaKind==`string`?{mediaKind:e.mediaKind}:{},...typeof e.capturedAt==`number`?{capturedAt:e.capturedAt}:{}}}var ke=[`resolving-image`,`connecting`,`first-token-wait`,`streaming`];function Ae(e){let t;try{t=JSON.parse(e)}catch{return null}if(!De(t))return null;switch(t.kind){case`status`:{let e=ke.find(e=>e===t.phase);return e===void 0?null:{kind:`status`,phase:e}}case`meta`:return typeof t.profileName!=`string`||typeof t.model!=`string`?null:{kind:`meta`,profileName:t.profileName,model:t.model,mediaSent:Oe(t.mediaSent),streamed:t.streamed===!0,firstTokenTimeoutMs:typeof t.firstTokenTimeoutMs==`number`?t.firstTokenTimeoutMs:0};case`token`:return typeof t.text==`string`?{kind:`token`,text:t.text}:null;case`done`:return{kind:`done`,inputTokens:typeof t.inputTokens==`number`?t.inputTokens:0,outputTokens:typeof t.outputTokens==`number`?t.outputTokens:0,latencyMs:typeof t.latencyMs==`number`?t.latencyMs:0,truncated:t.truncated===!0};case`error`:return{kind:`error`,code:typeof t.code==`string`?t.code:`adapter-error`,message:typeof t.message==`string`?t.message:`the provider returned an error`};default:return null}}async function*je(e){let t=e.getReader(),n=new TextDecoder,r=``;try{for(;;){let{done:e,value:i}=await t.read();if(e)break;r+=n.decode(i,{stream:!0});let a=r.indexOf(`
|
|
2
|
-
`);for(;a>=0;){let e=r.slice(0,a).trim();if(r=r.slice(a+1),e.length>0){let t=Ae(e);t!==null&&(yield t)}a=r.indexOf(`
|
|
3
|
-
`)}}let e=r.trim();if(e.length>0){let t=Ae(e);t!==null&&(yield t)}}finally{t.releaseLock()}}function Me(e){return e.filter(e=>e.failed!==!0&&e.content.length>0).map(e=>({role:e.role,content:e.content}))}function Ne(e){let t=e.sizeBytes<1024*1024?`${(e.sizeBytes/1024).toFixed(0)} KB`:`${(e.sizeBytes/(1024*1024)).toFixed(1)} MB`,n=[e.kind===`snapshot`?`camera snapshot`:`track best-shot`,t];return e.mediaKind!==void 0&&n.push(e.mediaKind),e.capturedAt!==void 0&&n.push(new Date(e.capturedAt).toLocaleTimeString()),n.join(` · `)}function Pe(e,t){switch(e){case`resolving-image`:return`fetching the picture…`;case`connecting`:return`connecting to the provider…`;case`first-token-wait`:return`waiting for the model — a cold load can take a while (up to ${String(Math.round(t/1e3))}s)`;case`streaming`:return`answering…`}}n();var Fe=[`deviceManager`,`listAll`,`cameras`],Ie=[`pipelineAnalytics`,`listRecentTracks`,`ai-test`],Le=360*60*1e3,Re=40,ze=160,$={phase:`connecting`,firstTokenTimeoutMs:0,text:``,mediaSent:null};function Be(){let{t:n}=G(),o=d(),[c,f]=s(``),[p,m]=s(``),[h,v]=s(``),[y,b]=s([]),[C,T]=s(null),[E,D]=s(`none`),[O,k]=s(null),[A,j]=s(null),P=t(null);u(()=>()=>P.current?.abort(),[]);let F=a({queryKey:J,queryFn:()=>o.trpcClient.llm.listProfiles.query({})}),I=i(()=>(F.data??[]).filter(e=>e.enabled),[F.data]),R=I.find(e=>e.id===c)??null,z=A!==null,V=e(async(e,t)=>{let r=new AbortController;P.current=r,k(null),j($);let i=``,a=null,o,s=null,l=null;try{let n=await fetch(Ee,{method:`POST`,headers:{"content-type":`application/json`},credentials:`same-origin`,signal:r.signal,body:JSON.stringify({profileId:c,messages:e,...p.trim()===``?{}:{system:p.trim()},...t===void 0?{}:{attachment:t}})});if(!n.ok||n.body===null){let e=await n.text().catch(()=>``);throw Error(e.length>0?e:`HTTP ${String(n.status)}`)}for await(let e of je(n.body))switch(e.kind){case`status`:j(t=>({...t??$,phase:e.phase}));break;case`meta`:a=e.mediaSent,o=e.model,j(t=>({...t??$,firstTokenTimeoutMs:e.firstTokenTimeoutMs,mediaSent:e.mediaSent}));break;case`token`:i+=e.text,j(e=>({...e??$,text:i}));break;case`done`:l={outputTokens:e.outputTokens,latencyMs:e.latencyMs};break;case`error`:s=`${e.code}: ${e.message}`;break}}catch(e){r.signal.aborted||k(e instanceof Error?e.message:n(`common.error`,`Error`))}finally{P.current=null,j(null)}let u=r.signal.aborted&&i.length>0;s===null&&i.length===0&&!u||b(e=>[...e,{id:`a-${String(Date.now())}`,role:`assistant`,content:s??i,...s===null?{}:{failed:!0},...a===null?{}:{attachment:a},...o!==void 0&&s===null?{model:o}:{},...l===null?{}:l}])},[c,p,n]),H=e(()=>{let e=h.trim();if(e===``||c===``||z)return;let t={id:`u-${String(Date.now())}`,role:`user`,content:e,...C===null?{}:{attachmentLabel:C.label,attachmentKind:C.ref.kind}},n=[...y,t];b(n),v(``);let r=C?.ref;T(null),D(`none`),V(Me(n),r)},[h,C,c,V,z,y]),W=()=>P.current?.abort();return r(K,{icon:M,title:n(`ai.testTitle`,`Test chat`),subtitle:n(`ai.testSubtitle`,`A throwaway conversation with one profile. Attach a live camera snapshot or a recent track to check the model can actually read a picture. Nothing is saved — only the usage row.`),actions:r(S,{size:`sm`,variant:`secondary`,type:`button`,disabled:y.length===0&&C===null,onClick:()=>{P.current?.abort(),b([]),T(null),v(``),k(null),j(null)},children:[l(te,{className:`h-3.5 w-3.5`}),n(`ai.clearChat`,`Clear`)]}),children:[r(_,{className:`space-y-3 p-4`,children:[r(`div`,{className:`grid gap-3 sm:grid-cols-2`,children:[r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-test-profile`,children:n(`ai.profile`,`Profile`)}),l(x,{id:`ai-test-profile`,value:c,onChange:e=>f(e.target.value),options:[{value:``,label:n(`ai.selectProfile`,`Select a profile…`)},...I.map(e=>({value:e.id,label:`${e.name} · ${e.model}${e.supportsVision?` · vision`:``}`}))]}),I.length===0&&!F.isLoading&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:n(`ai.noEnabledProfiles`,`No enabled profile. Add one on the Profiles tab.`)})]}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-test-system`,children:n(`ai.systemPrompt`,`System prompt (optional)`)}),l(g,{id:`ai-test-system`,value:p,onChange:e=>m(e.target.value),placeholder:n(`ai.systemPlaceholder`,`Answer in one short sentence.`)})]})]}),l(`p`,{className:`text-[10px] text-foreground-subtle`,children:n(`ai.streamNote`,`The answer streams as the model produces it. A cold model can take a while to load — the status line says which phase it is in.`)}),R!==null&&!R.supportsVision&&l(`p`,{className:`text-[10px] text-warning`,children:n(`ai.notVision`,`This profile is not vision-capable — an attached image will be refused before anything is read.`)})]}),O!==null&&l(w,{title:n(`ai.chatFailed`,`The test call failed`),message:O}),l(Ve,{turns:y,live:A}),r(_,{className:`space-y-2 p-3`,children:[C!==null&&r(`div`,{className:`flex items-center gap-2 rounded-md border border-border bg-surface px-2.5 py-1.5`,children:[C.ref.kind===`snapshot`?l(U,{className:`h-3.5 w-3.5 text-foreground-subtle`}):l(B,{className:`h-3.5 w-3.5 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-[11px] text-foreground`,children:C.label}),l(S,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>T(null),children:l(ee,{className:`h-3.5 w-3.5`})})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[r(S,{size:`sm`,variant:E===`snapshot`?`primary`:`outline`,type:`button`,onClick:()=>D(E===`snapshot`?`none`:`snapshot`),children:[l(U,{className:`h-3.5 w-3.5`}),n(`ai.attachSnapshot`,`Camera snapshot`)]}),r(S,{size:`sm`,variant:E===`track`?`primary`:`outline`,type:`button`,onClick:()=>D(E===`track`?`none`:`track`),children:[l(B,{className:`h-3.5 w-3.5`}),n(`ai.attachTrack`,`Recent track`)]})]}),E===`snapshot`&&l(Ue,{onPick:e=>{T({ref:{kind:`snapshot`,deviceId:e.id},label:n(`ai.snapshotOf`,`Snapshot of {{name}}`,{name:e.name})}),D(`none`)}}),E===`track`&&l(Ge,{onPick:(e,t)=>{T({ref:{kind:`track`,trackId:e.trackId},label:n(`ai.trackOf`,`{{class}} on {{name}}`,{class:e.label??e.className,name:t})}),D(`none`)}}),r(`div`,{className:`flex items-center gap-2`,children:[l(g,{value:h,onChange:e=>v(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),H())},placeholder:n(`ai.messagePlaceholder`,`Ask the model something…`),"aria-label":n(`ai.message`,`Message`)}),z?r(S,{size:`sm`,variant:`secondary`,type:`button`,onClick:W,children:[l(L,{className:`h-3.5 w-3.5`}),n(`ai.stop`,`Stop`)]}):r(S,{size:`sm`,type:`button`,disabled:h.trim()===``||c===``,onClick:H,children:[l(N,{className:`h-3.5 w-3.5`}),n(`ai.send`,`Send`)]})]})]})]})}function Ve({turns:e,live:t}){let{t:n}=G();return e.length===0&&t===null?l(`div`,{className:`py-12 text-center text-xs text-foreground-subtle`,children:n(`ai.chatEmpty`,`Pick a profile, optionally attach a camera snapshot or a recent track, and send a message. Nothing here is saved.`)}):l(_,{children:r(`div`,{className:`max-h-[50vh] space-y-2 overflow-y-auto p-3`,children:[e.map(e=>l(He,{turn:e},e.id)),t!==null&&r(`div`,{className:`space-y-1`,children:[t.text.length>0&&l(He,{turn:{id:`live`,role:`assistant`,content:t.text},streaming:!0}),r(`div`,{className:`flex items-center gap-2 text-[11px] text-foreground-subtle`,children:[l(R,{className:`h-3.5 w-3.5 animate-spin`}),Pe(t.phase,t.firstTokenTimeoutMs)]})]})]})})}function He({turn:e,streaming:t=!1}){let n=e.role===`user`,i=e.failed===!0?`border-danger/40 bg-danger/10`:`border-border bg-surface`;return l(`div`,{className:`flex ${n?`justify-end`:`justify-start`}`,children:r(`div`,{className:`max-w-[85%] rounded-lg border px-3 py-2 ${n?`border-primary/40 bg-primary/10`:i}`,children:[r(`p`,{className:`whitespace-pre-wrap break-words text-xs text-foreground`,children:[e.content,t&&l(`span`,{className:`ml-0.5 animate-pulse text-primary`,children:`▌`})]}),e.attachmentLabel!==void 0&&r(`p`,{className:`mt-1 flex items-center gap-1 text-[10px] text-foreground-subtle`,children:[e.attachmentKind===`track`?l(B,{className:`h-3 w-3`}):l(U,{className:`h-3 w-3`}),e.attachmentLabel]}),e.attachment!==void 0&&r(`p`,{className:`mt-1 flex items-center gap-1 text-[10px] text-foreground-subtle`,children:[e.attachment.kind===`snapshot`?l(U,{className:`h-3 w-3`}):l(B,{className:`h-3 w-3`}),Ne(e.attachment)]}),e.model!==void 0&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:`${e.model} · ${String(e.outputTokens??0)} tok · ${String(e.latencyMs??0)} ms`})]})})}function Ue({onPick:e}){let{t}=G(),n=d(),r=a({queryKey:Fe,queryFn:()=>n.trpcClient.deviceManager.listAll.query({isCamera:!0,projection:`slim`})}),i=(r.data??[]).filter(e=>!e.disabled);return r.isLoading?l(R,{className:`h-4 w-4 animate-spin text-foreground-subtle`}):i.length===0?l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`ai.noCameras`,`No camera found.`)}):l(`div`,{className:`grid max-h-56 grid-cols-2 gap-2 overflow-y-auto sm:grid-cols-4`,children:i.map(t=>l(We,{device:t,onPick:e},t.id))})}function We({device:e,onPick:t}){let{src:n}=f(e.id,{width:ze});return r(`button`,{type:`button`,onClick:()=>t(e),className:`overflow-hidden rounded-md border border-border bg-surface text-left transition-colors hover:border-primary/50`,children:[l(`span`,{className:`block aspect-video w-full bg-background-elevated`,children:n!==null&&l(`img`,{src:n,alt:``,className:`h-full w-full object-cover`,loading:`lazy`})}),r(`span`,{className:`flex items-center gap-1 px-2 py-1`,children:[!e.online&&l(y,{variant:`warning`,children:`off`}),l(`span`,{className:`truncate text-[10px] text-foreground`,children:e.name})]})]})}function Ge({onPick:e}){let{t}=G(),n=d(),o=a({queryKey:Fe,queryFn:()=>n.trpcClient.deviceManager.listAll.query({isCamera:!0,projection:`slim`})}),s=i(()=>(o.data??[]).map(e=>e.id),[o.data]),c=i(()=>{let e=new Map;for(let t of o.data??[])e.set(t.id,t.name);return e},[o.data]),u=a({queryKey:[...Ie,s.length],enabled:s.length>0,queryFn:()=>n.trpcClient.pipelineAnalytics.listRecentTracks.query({deviceIds:[...s],since:Date.now()-Le,limit:Re,projection:`slim`})});if(o.isLoading||u.isLoading)return l(R,{className:`h-4 w-4 animate-spin text-foreground-subtle`});let f=u.data?.tracks??[];return f.length===0?l(`p`,{className:`text-[11px] text-foreground-subtle`,children:t(`ai.noTracks`,`No track in the last 6 hours.`)}):l(`div`,{className:`max-h-56 divide-y divide-border overflow-y-auto rounded-md border border-border`,children:f.map(t=>r(`button`,{type:`button`,onClick:()=>e(t,c.get(t.deviceId)??String(t.deviceId)),className:`flex w-full items-center gap-2 px-2.5 py-1.5 text-left text-[11px] hover:bg-surface-hover`,children:[l(B,{className:`h-3.5 w-3.5 shrink-0 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-foreground`,children:t.label??t.className}),l(`span`,{className:`shrink-0 text-foreground-subtle`,children:c.get(t.deviceId)??t.deviceId}),l(`span`,{className:`shrink-0 text-foreground-subtle`,children:new Date(t.lastSeen).toLocaleTimeString()})]},t.trackId))})}n();var Ke=1440*60*1e3,qe=[1,7,30,90];function Je(){let{t:e}=G(),t=d(),[n,o]=s(7),c=i(()=>{let e=new Date;return e.setHours(0,0,0,0),e.getTime()-(n-1)*Ke},[n]),u=a({queryKey:J,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),f=a({queryKey:[...ce,n],queryFn:()=>t.trpcClient.llm.getUsage.query({since:c})}),p=i(()=>{let e=new Map;for(let t of u.data??[])e.set(t.id,t.name);return e},[u.data]),m=i(()=>[{key:`day`,header:e(`ai.colDay`,`Day`),nowrap:!0,render:e=>e.day},{key:`consumer`,header:e(`ai.colConsumer`,`Consumer`),nowrap:!0,render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:e.consumer})},{key:`profile`,header:e(`ai.colProfile`,`Profile`),render:e=>l(`span`,{className:`text-[11px] text-foreground`,children:p.get(e.profileId)??e.profileId})},{key:`calls`,header:e(`ai.colCalls`,`Calls`),align:`right`,nowrap:!0,render:e=>String(e.calls)},{key:`okErr`,header:e(`ai.colOkErr`,`OK / err`),align:`right`,nowrap:!0,render:e=>l(`span`,{className:e.errorCalls>0?`text-danger`:void 0,children:`${String(e.okCalls)} / ${String(e.errorCalls)}`})},{key:`tokens`,header:e(`ai.colTokens`,`In / out tok`),align:`right`,nowrap:!0,render:e=>`${String(e.inputTokens)} / ${String(e.outputTokens)}`},{key:`latency`,header:e(`ai.colAvgMs`,`Avg ms`),align:`right`,nowrap:!0,render:e=>String(Math.round(e.avgLatencyMs))}],[p,e]),h=f.data??[];return r(K,{icon:z,title:e(`ai.usageTitle`,`Usage`),subtitle:e(`ai.usageSubtitle`,`Server-side rollup per day, consumer and profile — never raw call rows. Errors are counted, so a profile that always fails is visible here before a feature reports it.`),actions:l(`div`,{className:`w-40`,children:l(x,{"aria-label":e(`ai.window`,`Window`),value:String(n),options:qe.map(t=>({value:String(t),label:e(`ai.lastDays`,`Last {{days}} days`,{days:t})})),onChange:e=>o(Number(e.target.value))})}),children:[f.isError&&l(w,{title:e(`ai.usageFailed`,`Failed to read usage`),message:f.error instanceof Error?f.error.message:e(`common.error`,`Error`),onRetry:()=>void f.refetch()}),h.length===0?l(`div`,{className:`py-16 text-center text-xs text-foreground-subtle`,children:e(`ai.noUsage`,`No AI calls in this window.`)}):l(_,{children:l(k,{columns:m,rows:h,rowKey:e=>`${e.day}|${e.consumer}|${e.profileId}`,minWidthPx:720,bordered:!1,mobileMode:`scroll`,maxBodyHeight:O})})]})}function Ye(){let{t:e}=G();return l(`div`,{className:`flex flex-col p-4`,children:l(re,{tabs:[{id:`profiles`,label:e(`ai.tabProfiles`,`Profiles`),icon:j,content:l(xe,{})},{id:`runtimes`,label:e(`ai.tabRuntimes`,`Runtimes`),icon:I,content:l(Te,{})},{id:`usage`,label:e(`ai.tabUsage`,`Usage`),icon:z,content:l(Je,{})},{id:`test`,label:e(`ai.tabTest`,`Test`),icon:M,content:l(Be,{})}]})})}export{Ye as AiProfilesPage,Ye as default};
|