@camstack/addon-admin-ui 1.2.62 → 1.2.64
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-I8kBbXKL.js → AddLocationWizard-Rtx2w8Ge.js} +1 -1
- package/dist/assets/{AddonCollectionPage-KrivzOtq.js → AddonCollectionPage-CRMi8Hpy.js} +1 -1
- package/dist/assets/{Addons-D_HB3Gz6.js → Addons-DrGoA3sf.js} +1 -1
- package/dist/assets/{AdminTabs-T4tXzr6m.js → AdminTabs-DPygIgVT.js} +1 -1
- package/dist/assets/AiProfiles-Cau0z0rv.js +3 -0
- package/dist/assets/{BrokerForm-B8GkNs2Z.js → BrokerForm-CNS8TLW1.js} +1 -1
- package/dist/assets/{Build-B-Jg80Db.js → Build-p2UrTXXB.js} +1 -1
- package/dist/assets/{Capabilities-KvgWF7xs.js → Capabilities-CBelMVi9.js} +1 -1
- package/dist/assets/{CapabilityBadges-CDULR6Ww.js → CapabilityBadges-CePOZ9pv.js} +1 -1
- package/dist/assets/{Cluster-BtFDl4d9.js → Cluster-CKJ4Di2k.js} +1 -1
- package/dist/assets/{Data-CxxsTdTH.js → Data-DQN08Osn.js} +1 -1
- package/dist/assets/{DetectionIntelligence-DFpsI2re.js → DetectionIntelligence-3W-QsAKt.js} +1 -1
- package/dist/assets/{DeviceAggregateSection-Bwo1fvlT.js → DeviceAggregateSection-CN7PswWV.js} +1 -1
- package/dist/assets/{DeviceDetail-BLZw49Iz.js → DeviceDetail-CvfaMldw.js} +1 -1
- package/dist/assets/{Devices-BQ-a1X4I.js → Devices-ekrIigG7.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-D7ZQ6n8q.js → EmbedPlayerPage-BI2AGOPB.js} +1 -1
- package/dist/assets/{Events-CnrHHUoS.js → Events-dfb6f9u9.js} +1 -1
- package/dist/assets/{FormBuilder-BCPJkQ63.js → FormBuilder-DC09MD8z.js} +1 -1
- package/dist/assets/{Identity-Co5glfeQ.js → Identity-DMvDr3fz.js} +1 -1
- package/dist/assets/{IntegrationDetail-BxeX15Pm.js → IntegrationDetail-DmYaRumv.js} +1 -1
- package/dist/assets/{Integrations-CA8jB6CT.js → Integrations-BWV9LK2_.js} +1 -1
- package/dist/assets/{Integrations-BfKnikwe.js → Integrations-CntkGNRq.js} +1 -1
- package/dist/assets/{Logs-TioRBvTP.js → Logs-DmhrO61-.js} +1 -1
- package/dist/assets/{MotionZonesSettings-DXhni28t.js → MotionZonesSettings-Bh5Pjl_Y.js} +1 -1
- package/dist/assets/{MyAccess-BhxYSV_l.js → MyAccess-DeKpJLjj.js} +1 -1
- package/dist/assets/{Network-WkehLI9m.js → Network-nRbvH88f.js} +1 -1
- package/dist/assets/{NodeAddonsSettingsPanel-iAVvOCGv.js → NodeAddonsSettingsPanel-B9GdHeQO.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-CwI9ek65.js → NodeInferenceDevices-DIbWSF6N.js} +1 -1
- package/dist/assets/{Notifications-DntoQaM6.js → Notifications-DPGgZRkO.js} +1 -1
- package/dist/assets/{Pipeline-CecRYpzk.js → Pipeline-CHfPE4zw.js} +1 -1
- package/dist/assets/{Plates-CG_WFsXV.js → Plates-DjHIRX11.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-DYJCefRc.js → PrivacyMaskSettings-BSFzMp1X.js} +1 -1
- package/dist/assets/{ProviderIcon-y1m8BuFZ.js → ProviderIcon-uiUuYEst.js} +1 -1
- package/dist/assets/{Recordings-Bd-VF9gP.js → Recordings-B8SloOkL.js} +1 -1
- package/dist/assets/{ScanNetworkModal-ByHfMRVr.js → ScanNetworkModal-DnvSvL3H.js} +1 -1
- package/dist/assets/{SceneMonitorEditor-B-vpudbK.js → SceneMonitorEditor-Ck1EyLTi.js} +1 -1
- package/dist/assets/{Scenes-C1eh3JuE.js → Scenes-CoFARtT2.js} +1 -1
- package/dist/assets/{Settings-BztTE2tp.js → Settings-srwQ29Zm.js} +1 -1
- package/dist/assets/{Showroom-POB0_SpW.js → Showroom-FdSkNLM7.js} +1 -1
- package/dist/assets/{Terminal-33TmgWoS.js → Terminal-lR1PtLfa.js} +1 -1
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-CwqT4DOs.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-Ceb4j9T3.js} +1 -1
- package/dist/assets/{bell-ring-DPD6sMve.js → bell-ring-2GuVPUMV.js} +1 -1
- package/dist/assets/{boxes-D4otfCdM.js → boxes-Cv1y4Bzc.js} +1 -1
- package/dist/assets/{build-cluster-graph-HhTcae8G.js → build-cluster-graph-BEIOSj-q.js} +1 -1
- package/dist/assets/circle-check-big-dTS9q1Zi.js +1 -0
- package/dist/assets/{circle-x-U6SWO2IP.js → circle-x-yDCV4dJs.js} +1 -1
- package/dist/assets/clock-BZHOxtKN.js +1 -0
- package/dist/assets/{copy-CMcitcxu.js → copy-BzvPXBQa.js} +1 -1
- package/dist/assets/{debounced-invalidate-CHwSuvzf.js → debounced-invalidate--vYgOSs8.js} +1 -1
- package/dist/assets/{dist-DaBaoyDk.js → dist-B3abLTAk.js} +1 -1
- package/dist/assets/dist-jUZC7DhT.js +345 -0
- package/dist/assets/{download-ge4FL0UH.js → download-ZEauntF-.js} +1 -1
- package/dist/assets/{face-bbox-Db31_MCB.js → face-bbox-Cvff56YN.js} +1 -1
- package/dist/assets/{hard-drive-BjTbYotH.js → hard-drive-vk5wyQE5.js} +1 -1
- package/dist/assets/{hostInit-COiRp72S.js → hostInit-B81OBEcL.js} +1 -1
- package/dist/assets/{index-B8gfFLO3.js → index-CbTjMrYx.js} +3 -3
- package/dist/assets/{key-round-DRN-KYrp.js → key-round-CW2EaBMX.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-cc2983c3.js → mf-entry-bootstrap-0-f99faee4.js} +2 -2
- package/dist/assets/{pencil-CCTI-4rI.js → pencil-XI_43st4.js} +1 -1
- package/dist/assets/play-DDV73FUi.js +1 -0
- package/dist/assets/{player-overlays-DTulF4Wm.js → player-overlays-C89ysycJ.js} +1 -1
- package/dist/assets/plus-CInUrJd7.js +1 -0
- package/dist/assets/power-2AvrvxPl.js +1 -0
- package/dist/assets/{radio-DxJgUT8d.js → radio-rZ8qayNX.js} +1 -1
- package/dist/assets/{refresh-cw-CIsX4AtN.js → refresh-cw-4m2P1KWX.js} +1 -1
- package/dist/assets/remoteEntry-Bz9gcjD-.js +1 -0
- package/dist/assets/rotate-ccw-BOvw_QMX.js +1 -0
- package/dist/assets/rotate-cw-D5AfagzL.js +1 -0
- package/dist/assets/search-Cn4Sp_ZB.js +1 -0
- package/dist/assets/{send-D-EllYB0.js → send-CqFJrG4o.js} +1 -1
- package/dist/assets/{server-BTc5FZH2.js → server-xGGeh4GQ.js} +1 -1
- package/dist/assets/{square-check-big-BR_fEref.js → square-check-big-ChrSTyBa.js} +1 -1
- package/dist/assets/square-gU59rjC6.js +1 -0
- package/dist/assets/src-ByBn7YGK.js +345 -0
- package/dist/assets/src-DJ5lhM9h.js +67 -0
- package/dist/assets/{undo-2-C3TKGI8Q.js → undo-2-CCsVR_hG.js} +1 -1
- package/dist/assets/{upload-BDphFIfP.js → upload-CqTYxUpd.js} +1 -1
- package/dist/assets/{use-scenes-feed-gNX_X7lL.js → use-scenes-feed-BwCEYdwU.js} +1 -1
- package/dist/assets/{useEventInvalidation-DxrL9t2b.js → useEventInvalidation-PP_z4Ptm.js} +1 -1
- package/dist/assets/{video-DIq9FtAl.js → video-oj6ReSiz.js} +1 -1
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-BiWwXNnq.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-BwjddgUO.js} +2 -2
- package/dist/assets/{wifi-CAt114K2.js → wifi-BEqdJPGy.js} +1 -1
- package/dist/assets/{zap-Css9POSH.js → zap-CPBaAYNY.js} +1 -1
- package/dist/index.html +5 -5
- package/dist/server/addon.js +163 -4
- package/package.json +1 -1
- package/dist/assets/AiProfiles-DWhKAjFC.js +0 -3
- package/dist/assets/circle-check-big-CQf8q4ZY.js +0 -1
- package/dist/assets/clock-BzxnvWco.js +0 -1
- package/dist/assets/dist-CqpztYBE.js +0 -345
- package/dist/assets/play-CO2t37JV.js +0 -1
- package/dist/assets/plus-el6mwbuy.js +0 -1
- package/dist/assets/power-DSbj5xjk.js +0 -1
- package/dist/assets/remoteEntry-CZM3JGNn.js +0 -1
- package/dist/assets/rotate-ccw-vrvftCHH.js +0 -1
- package/dist/assets/rotate-cw-DnaKkb_h.js +0 -1
- package/dist/assets/search-D_IrNll3.js +0 -1
- package/dist/assets/square-7qF8nU-R.js +0 -1
- package/dist/assets/src-ZxR8RVbo.js +0 -67
- package/dist/assets/src-_Z89-Z6-.js +0 -345
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(),
|
|
@@ -12490,6 +12543,36 @@ var ManagedModelCatalogEntrySchema = object({
|
|
|
12490
12543
|
/** Vision models: companion projector file. */
|
|
12491
12544
|
mmprojUrl: string().optional()
|
|
12492
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
|
+
})]);
|
|
12493
12576
|
var LlmRuntimeNodeSchema = object({
|
|
12494
12577
|
nodeId: string(),
|
|
12495
12578
|
reachable: boolean(),
|
|
@@ -12526,6 +12609,15 @@ method(LlmGenerateBaseInputSchema, LlmGenerateResultSchema, { kind: "mutation" }
|
|
|
12526
12609
|
consumer: string().optional(),
|
|
12527
12610
|
profileId: string().optional()
|
|
12528
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({
|
|
12529
12621
|
nodeId: string(),
|
|
12530
12622
|
model: ManagedModelRefSchema
|
|
12531
12623
|
}), _void(), {
|
|
@@ -17658,6 +17750,17 @@ var maxSessionHoldMsField = {
|
|
|
17658
17750
|
default: 12e4,
|
|
17659
17751
|
step: 5e3
|
|
17660
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
|
+
};
|
|
17661
17764
|
var motionFpsField = {
|
|
17662
17765
|
min: 1,
|
|
17663
17766
|
max: 30,
|
|
@@ -17834,6 +17937,27 @@ var RunnerCameraConfigSchema = object({
|
|
|
17834
17937
|
* resolved `CameraDetectionConfig`.
|
|
17835
17938
|
*/
|
|
17836
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(),
|
|
17837
17961
|
motionFps: number().min(motionFpsField.min).max(motionFpsField.max).default(motionFpsField.default),
|
|
17838
17962
|
detectionFps: number().min(detectionFpsField.min).max(detectionFpsField.max).default(detectionFpsField.default),
|
|
17839
17963
|
motionStreamId: string(),
|
|
@@ -17929,7 +18053,7 @@ var RunnerCameraConfigSchema = object({
|
|
|
17929
18053
|
*/
|
|
17930
18054
|
inferenceDevices: array(RunnerInferenceDeviceSchema).readonly().optional()
|
|
17931
18055
|
});
|
|
17932
|
-
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;
|
|
17933
18057
|
/**
|
|
17934
18058
|
* Runtime load summary returned by `getLocalLoad`. Used by the orchestrator's
|
|
17935
18059
|
* load-balancing levels (L2 capacity-based, L3 hardware-aware) to decide
|
|
@@ -20467,6 +20591,25 @@ var BatteryStatusSchema = object({
|
|
|
20467
20591
|
/** Ms epoch of the last observation. Lets consumers reason about freshness. */
|
|
20468
20592
|
lastUpdated: number(),
|
|
20469
20593
|
/**
|
|
20594
|
+
* Ms epoch of the last time the device PROVED it was reachable — a
|
|
20595
|
+
* completed firmware round-trip, an observed wake, or an inbound push
|
|
20596
|
+
* (firmware event, email). `0`/absent = never since this slice was born.
|
|
20597
|
+
*
|
|
20598
|
+
* This is the ONLY input that separates "asleep" from "gone", and it is
|
|
20599
|
+
* fed exclusively by PASSIVE signals: nothing may write it by reaching
|
|
20600
|
+
* for the radio, because a poll that confirms reachability is the same
|
|
20601
|
+
* poll that drains the battery. See {@link deriveBatteryPresence} — the
|
|
20602
|
+
* single derivation every consumer must use; no surface computes its own.
|
|
20603
|
+
*
|
|
20604
|
+
* It is deliberately NOT a clock in the
|
|
20605
|
+
* `scripts/check-runtime-state-durability.ts` sense: it is the
|
|
20606
|
+
* observation itself, and it is the only thing a 30-hour silence is
|
|
20607
|
+
* visible in. Writers quantise it (see `CONTACT_WRITE_QUANTUM_MS` in the
|
|
20608
|
+
* Reolink provider) so a value that means "recently" cannot cost a
|
|
20609
|
+
* SQLite commit per round-trip.
|
|
20610
|
+
*/
|
|
20611
|
+
lastContactAt: number().optional(),
|
|
20612
|
+
/**
|
|
20470
20613
|
* True when the source is a BINARY low-battery indicator (HA
|
|
20471
20614
|
* `binary_sensor` device_class=battery / `LOW_BAT`) that has no real
|
|
20472
20615
|
* charge level — `percentage` is then a coarse stand-in (100 = normal,
|
|
@@ -24744,6 +24887,16 @@ var CamStreamDescriptorSchema = object({
|
|
|
24744
24887
|
/** Transport-specific opaque metadata (e.g. rfc4571 SDP). */
|
|
24745
24888
|
metadata: record(string(), unknown()).optional()
|
|
24746
24889
|
});
|
|
24890
|
+
object({
|
|
24891
|
+
/** The descriptors as last built from a real camera response. Never a guess:
|
|
24892
|
+
* a failed or refused build writes NOTHING, so a restored catalog is always
|
|
24893
|
+
* one the camera itself once produced. */
|
|
24894
|
+
descriptors: array(CamStreamDescriptorSchema),
|
|
24895
|
+
/** Ms epoch of the build that produced {@link descriptors}. Lets the wake
|
|
24896
|
+
* path decide whether the camera's own awake window is worth spending on a
|
|
24897
|
+
* re-read. */
|
|
24898
|
+
lastFetchedAt: number()
|
|
24899
|
+
});
|
|
24747
24900
|
DeviceType.Camera, method(object({ deviceId: number().int().nonnegative() }), array(CamStreamDescriptorSchema).readonly());
|
|
24748
24901
|
/** One of the camera's stream profiles. */
|
|
24749
24902
|
var StreamProfileSchema = _enum([
|
|
@@ -27776,6 +27929,12 @@ Object.freeze({
|
|
|
27776
27929
|
addonId: null,
|
|
27777
27930
|
access: "view"
|
|
27778
27931
|
},
|
|
27932
|
+
"llm.resolveModelRef": {
|
|
27933
|
+
capName: "llm",
|
|
27934
|
+
capScope: "system",
|
|
27935
|
+
addonId: null,
|
|
27936
|
+
access: "create"
|
|
27937
|
+
},
|
|
27779
27938
|
"llm.setDefault": {
|
|
27780
27939
|
capName: "llm",
|
|
27781
27940
|
capScope: "system",
|
|
@@ -33331,7 +33490,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
33331
33490
|
capability: adminUiCapability,
|
|
33332
33491
|
provider: {
|
|
33333
33492
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
33334
|
-
getVersion: async () => ({ version: "1.2.
|
|
33493
|
+
getVersion: async () => ({ version: "1.2.64" })
|
|
33335
33494
|
}
|
|
33336
33495
|
}];
|
|
33337
33496
|
}
|
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-DTulF4Wm.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-ZxR8RVbo.js";import{K as A}from"./src-_Z89-Z6-.js";import{t as j}from"./boxes-D4otfCdM.js";import{n as M,t as N}from"./send-D-EllYB0.js";import{t as P}from"./pencil-CCTI-4rI.js";import{t as F}from"./plus-el6mwbuy.js";import{t as I}from"./server-BTc5FZH2.js";import{t as ee}from"./square-7qF8nU-R.js";import{C as L,D as R,H as z,K as B,N as V,V as H,i as te,l as ne,s as re,t as U,v as ie}from"./index-B8gfFLO3.js";import{t as W}from"./AdminPage-CCD07UMs.js";import{t as ae}from"./AdminTabs-T4tXzr6m.js";var G=B(`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 K=[`llm`,`listProfiles`],oe=[`llm`,`listProfileKinds`],se=[`llm`,`getDefaults`],ce=[`llm`,`listRuntimeNodes`],le=[`llm`,`listModelCatalog`],ue=[`llm`,`getUsage`],de=[{purpose:`vision`,visionOnly:!0},{purpose:`text`,visionOnly:!1}],fe=new Map(Object.entries({openai:G,anthropic:G,google:G,"openai-compatible":ie,"managed-local":V}));function pe(e){return fe.get(e)??null}function q(e){return typeof e==`string`&&e.length>0?e:void 0}function J(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 Y(e){return e===!0}function me(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 he=[`f32`,`f16`,`q8_0`,`q5_1`,`q5_0`,`q4_1`,`q4_0`];function ge(e){return typeof e==`string`&&he.includes(e)?e:void 0}function _e(e,t,n){let r=J(e.threads),i=J(e.batchSize),a=J(e.ubatchSize),o=ge(e.cacheTypeK),s=ge(e.cacheTypeV);return{nodeId:t,engine:`llama-cpp`,model:{kind:`catalog`,catalogId:n},contextSize:J(e.contextSize)??4096,gpuLayers:J(e.gpuLayers)??0,...r===void 0?{}:{threads:r},parallel:J(e.parallel)??1,...i===void 0?{}:{batchSize:i},...a===void 0?{}:{ubatchSize:a},flashAttention:Y(e.flashAttention),mlock:Y(e.mlock),noMmap:Y(e.noMmap),...o===void 0?{}:{cacheTypeK:o},...s===void 0?{}:{cacheTypeV:s},autoStart:Y(e.autoStart),idleStopMinutes:J(e.idleStopMinutes)??30}}function ve(e,t,n,r,i){let a={id:n?.id??crypto.randomUUID(),name:t,kind:e,addonId:`ai`,enabled:n?.enabled??!0,model:q(r.model)??n?.model??``,supportsVision:i?.supportsVision??Y(r.supportsVision),timeoutMs:J(r.timeoutMs)??A.totalMs,connectTimeoutMs:J(r.connectTimeoutMs)??A.connectMs,firstTokenTimeoutMs:J(r.firstTokenTimeoutMs)??A.firstTokenMs,idleTimeoutMs:J(r.idleTimeoutMs)??A.idleMs,retry:{enabled:Y(r.retryEnabled),maxAttempts:J(r.retryMaxAttempts)??1},toolsEnabled:Y(r.toolsEnabled)},o=q(r.baseUrl),s=q(r.apiKey),c=J(r.temperature),l=J(r.topP),u=J(r.topK),d=J(r.maxTokens),f=J(r.contextLength),p=q(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:_e(r,i.nodeId,i.catalogId)}}}function ye(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 X({kind:e,className:t}){let n=pe(e.kind);return n===null?l(`span`,{className:t,children:e.icon}):l(n,{className:t})}function be({kinds:e,onPick:t,onCancel:n}){let{t:a}=U(),o=i(()=>ye(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(X,{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 xe({kind:e,existing:t,onSave:n,onCancel:c,saving:u,error:f}){let{t:_}=U(),b=d(),w=e.kind===`managed-local`,[O,k]=s(t?.name??e.label),[A,j]=s(()=>t===null?{}:me(t)),[M,N]=s(t?.runtime?.nodeId??`hub`),[P,F]=s(t?.runtime?.model.kind===`catalog`?t.runtime.model.catalogId:``),I=a({queryKey:le,enabled:w,queryFn:()=>b.trpcClient.llm.listModelCatalog.query({})}),ee=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,_]),R=()=>{if(!w){n(ve(e.kind,O,t,A));return}let r=I.data?.find(e=>e.id===P);n(ve(e.kind,O,t,A,{nodeId:M,catalogId:P,supportsVision:r?.purpose===`vision`}))},z=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(X,{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:ee,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:z,onClick:R,children:[u&&l(L,{className:`h-3.5 w-3.5 animate-spin`}),t===null?_(`ai.createProfile`,`Create profile`):_(`ai.saveChanges`,`Save changes`)]})]})]})})}n();function Se(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(X,{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(L,{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(re,{className:`h-3.5 w-3.5 text-danger`})})]})}]}function Ce(){let{t:e}=U(),t=d(),[n,o]=s({mode:`closed`}),[u,f]=s(null),[p,m]=s(null),h=a({queryKey:K,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),g=a({queryKey:oe,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(W,{icon:ne,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(we,{profiles:C}),h.isLoading&&l(`div`,{className:`flex items-center justify-center py-16`,children:l(L,{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:Se({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(be,{kinds:T,onCancel:()=>o({mode:`closed`}),onPick:e=>o({mode:`form`,kind:e,profile:null})}),n.mode===`form`&&l(xe,{kind:n.kind,existing:n.profile,saving:y.isPending,error:p,onSave:e=>y.mutate(e),onCancel:()=>o({mode:`closed`})})]})}function we({profiles:e}){let{t}=U(),n=d(),i=a({queryKey:se,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:de.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 Te=5e3;function Ee(e){return`${(e/1e9).toFixed(1)} GB`}function De(){let{t:e}=U(),t=d(),n=a({queryKey:ce,refetchInterval:Te,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?`—`:Ee(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(W,{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 Oe=`/addon/ai/test-chat`,ke=6e5;function Ae(e){let t=e.firstTokenTimeoutMs;if(!(typeof t!=`number`||!Number.isFinite(t)||t<=0))return Math.min(Math.round(t),ke)}function je(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Me(e){if(!je(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 Ne=[`resolving-image`,`connecting`,`first-token-wait`,`streaming`];function Pe(e){let t;try{t=JSON.parse(e)}catch{return null}if(!je(t))return null;switch(t.kind){case`status`:{let e=Ne.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:Me(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*Fe(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=Pe(e);t!==null&&(yield t)}a=r.indexOf(`
|
|
3
|
-
`)}}let e=r.trim();if(e.length>0){let t=Pe(e);t!==null&&(yield t)}}finally{t.releaseLock()}}function Ie(e){return e.filter(e=>e.failed!==!0&&e.content.length>0).map(e=>({role:e.role,content:e.content}))}function Le(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 Re(e,t){switch(e){case`resolving-image`:return`fetching the picture…`;case`connecting`:return`connecting to the provider…`;case`first-token-wait`:return t>0?`the model is loading / thinking — a cold load can take minutes (up to ${String(Math.round(t/1e3))}s)`:`the model is loading / thinking — a cold load can take minutes`;case`streaming`:return`answering…`}}n();var ze=[`deviceManager`,`listAll`,`cameras`],Be=[`pipelineAnalytics`,`listRecentTracks`,`ai-test`],Ve=360*60*1e3,He=40,Ue=160,Z={phase:`connecting`,firstTokenTimeoutMs:0,text:``,mediaSent:null};function We(){let{t:n}=U(),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:K,queryFn:()=>o.trpcClient.llm.listProfiles.query({})}),I=i(()=>(F.data??[]).filter(e=>e.enabled),[F.data]),L=I.find(e=>e.id===c)??null,R=A!==null,B=e(async(e,t)=>{let r=new AbortController;P.current=r,k(null);let i=Ae(L??{});j({...Z,firstTokenTimeoutMs:i??0});let a=``,o=null,s,l=null,u=null;try{let n=await fetch(Oe,{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},...i===void 0?{}:{firstTokenTimeoutMs:i}})});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 Fe(n.body))switch(e.kind){case`status`:j(t=>({...t??Z,phase:e.phase}));break;case`meta`:o=e.mediaSent,s=e.model,j(t=>({...t??Z,firstTokenTimeoutMs:e.firstTokenTimeoutMs,mediaSent:e.mediaSent}));break;case`token`:a+=e.text,j(e=>({...e??Z,text:a}));break;case`done`:u={outputTokens:e.outputTokens,latencyMs:e.latencyMs};break;case`error`:l=`${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 d=r.signal.aborted&&a.length>0;l===null&&a.length===0&&!d||b(e=>[...e,{id:`a-${String(Date.now())}`,role:`assistant`,content:l??a,...l===null?{}:{failed:!0},...o===null?{}:{attachment:o},...s!==void 0&&l===null?{model:s}:{},...u===null?{}:u}])},[L,c,p,n]),V=e(()=>{let e=h.trim();if(e===``||c===``||R)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`),B(Ie(n),r)},[h,C,c,B,R,y]),ne=()=>P.current?.abort();return r(W,{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(re,{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.`)}),L!==null&&!L.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(Ge,{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(H,{className:`h-3.5 w-3.5 text-foreground-subtle`}):l(z,{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(te,{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(H,{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(z,{className:`h-3.5 w-3.5`}),n(`ai.attachTrack`,`Recent track`)]})]}),E===`snapshot`&&l(Ke,{onPick:e=>{T({ref:{kind:`snapshot`,deviceId:e.id},label:n(`ai.snapshotOf`,`Snapshot of {{name}}`,{name:e.name})}),D(`none`)}}),E===`track`&&l(Je,{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(),V())},placeholder:n(`ai.messagePlaceholder`,`Ask the model something…`),"aria-label":n(`ai.message`,`Message`)}),R?r(S,{size:`sm`,variant:`secondary`,type:`button`,onClick:ne,children:[l(ee,{className:`h-3.5 w-3.5`}),n(`ai.stop`,`Stop`)]}):r(S,{size:`sm`,type:`button`,disabled:h.trim()===``||c===``,onClick:V,children:[l(N,{className:`h-3.5 w-3.5`}),n(`ai.send`,`Send`)]})]})]})]})}function Ge({turns:e,live:t}){let{t:n}=U();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(Q,{turn:e},e.id)),t!==null&&r(`div`,{className:`space-y-1`,children:[t.text.length>0&&l(Q,{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(L,{className:`h-3.5 w-3.5 animate-spin`}),Re(t.phase,t.firstTokenTimeoutMs)]})]})]})})}function Q({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(z,{className:`h-3 w-3`}):l(H,{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(H,{className:`h-3 w-3`}):l(z,{className:`h-3 w-3`}),Le(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 Ke({onPick:e}){let{t}=U(),n=d(),r=a({queryKey:ze,queryFn:()=>n.trpcClient.deviceManager.listAll.query({isCamera:!0,projection:`slim`})}),i=(r.data??[]).filter(e=>!e.disabled);return r.isLoading?l(L,{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(qe,{device:t,onPick:e},t.id))})}function qe({device:e,onPick:t}){let{src:n}=f(e.id,{width:Ue});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 Je({onPick:e}){let{t}=U(),n=d(),o=a({queryKey:ze,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:[...Be,s.length],enabled:s.length>0,queryFn:()=>n.trpcClient.pipelineAnalytics.listRecentTracks.query({deviceIds:[...s],since:Date.now()-Ve,limit:He,projection:`slim`})});if(o.isLoading||u.isLoading)return l(L,{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(z,{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 Ye=1440*60*1e3,Xe=[1,7,30,90];function Ze(){let{t:e}=U(),t=d(),[n,o]=s(7),c=i(()=>{let e=new Date;return e.setHours(0,0,0,0),e.getTime()-(n-1)*Ye},[n]),u=a({queryKey:K,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),f=a({queryKey:[...ue,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(W,{icon:R,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:Xe.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 $(){let{t:e}=U();return l(`div`,{className:`flex flex-col p-4`,children:l(ae,{tabs:[{id:`profiles`,label:e(`ai.tabProfiles`,`Profiles`),icon:j,content:l(Ce,{})},{id:`runtimes`,label:e(`ai.tabRuntimes`,`Runtimes`),icon:I,content:l(De,{})},{id:`usage`,label:e(`ai.tabUsage`,`Usage`),icon:R,content:l(Ze,{})},{id:`test`,label:e(`ai.tabTest`,`Test`),icon:M,content:l(We,{})}]})})}export{$ as AiProfilesPage,$ as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{K as e}from"./index-B8gfFLO3.js";var t=e(`circle-check-big`,[[`path`,{d:`M21.801 10A10 10 0 1 1 17 3.335`,key:`yps3ct`}],[`path`,{d:`m9 11 3 3L22 4`,key:`1pflzl`}]]);export{t};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{K as e}from"./index-B8gfFLO3.js";var t=e(`clock`,[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`polyline`,{points:`12 6 12 12 16 14`,key:`68esgv`}]]);export{t};
|