@camstack/addon-admin-ui 1.2.264 → 1.2.266
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/{AddonCollectionPage-CX0Adg6B.js → AddonCollectionPage-CH9hGNsl.js} +1 -1
- package/dist/assets/{Addons-BaAPnlPN.js → Addons-X99-jWIv.js} +1 -1
- package/dist/assets/{AdminTabs-BGbLei2R.js → AdminTabs-CYf73mcj.js} +1 -1
- package/dist/assets/AiProfiles-CufCtwdR.js +3 -0
- package/dist/assets/{BrokerForm-CRihFbyu.js → BrokerForm-DwGhDxrN.js} +1 -1
- package/dist/assets/{Build-DKSPDIw-.js → Build-BcXP2_Y6.js} +3 -3
- package/dist/assets/{Capabilities-CD-fgbZL.js → Capabilities-B9uMfM8F.js} +1 -1
- package/dist/assets/{CapabilityBadges-D4CBiW5c.js → CapabilityBadges-Ct0inpgH.js} +1 -1
- package/dist/assets/{Cluster-CSrIoNo1.js → Cluster-rHjZM17h.js} +1 -1
- package/dist/assets/{Data-C34owvxb.js → Data-6q4IrgiO.js} +1 -1
- package/dist/assets/{DetectionIntelligence-CZChZWCz.js → DetectionIntelligence-rRyquGIU.js} +1 -1
- package/dist/assets/{DeviceAggregateSection-CLs7WHnI.js → DeviceAggregateSection-BewPZ0sX.js} +1 -1
- package/dist/assets/{DeviceDetail-DIjq23w6.js → DeviceDetail-BZnajsi4.js} +2 -2
- package/dist/assets/{Devices-kY906D1O.js → Devices-Dcnq_aGP.js} +1 -1
- package/dist/assets/{EmbedPlayerPage-BvMSazzK.js → EmbedPlayerPage-CSI6tdlW.js} +1 -1
- package/dist/assets/{Events-Co4b2x10.js → Events-CmI5AZ3S.js} +1 -1
- package/dist/assets/{FormBuilder-DA7hQ1Xt.js → FormBuilder-WQFPFTW5.js} +1 -1
- package/dist/assets/{Identity--EbiVK1Q.js → Identity-ChZKnMoO.js} +1 -1
- package/dist/assets/{IntegrationDetail-BAZLswi9.js → IntegrationDetail-C6a5DNTQ.js} +1 -1
- package/dist/assets/Integrations-B1y3lr-7.js +1 -0
- package/dist/assets/{Integrations-CDdK3f30.js → Integrations-BsaYvGqF.js} +1 -1
- package/dist/assets/{Locations-C81oKLmH.js → Locations-DlDjZxSv.js} +2 -2
- package/dist/assets/{Logs-RoaxtEya.js → Logs-DTYBczsw.js} +1 -1
- package/dist/assets/{MotionZonesSettings-D1gJv8PU.js → MotionZonesSettings-E1rpEAhz.js} +1 -1
- package/dist/assets/{MyAccess-B0G0XNPz.js → MyAccess-C8OY0BtW.js} +1 -1
- package/dist/assets/{Network-B1VgCAY6.js → Network-QocgpPKi.js} +1 -1
- package/dist/assets/{NodeAddonsSettingsPanel-2DU4wzq-.js → NodeAddonsSettingsPanel-1JQaJsCE.js} +1 -1
- package/dist/assets/{NodeInferenceDevices-CqddQOH1.js → NodeInferenceDevices-C1sPl_zK.js} +1 -1
- package/dist/assets/Notifications-DN0lnKy8.js +1 -0
- package/dist/assets/{Pipeline-Dipm61ke.js → Pipeline-CgGpYxcl.js} +1 -1
- package/dist/assets/{Plates-BE5wRh5f.js → Plates-DmPIKCi6.js} +1 -1
- package/dist/assets/{PrivacyMaskSettings-BafWGIBw.js → PrivacyMaskSettings-Di4BC6vd.js} +1 -1
- package/dist/assets/{ProviderIcon-DH423BHN.js → ProviderIcon-CalACBCv.js} +1 -1
- package/dist/assets/{Recordings-5CB-NCHk.js → Recordings-LG_EAP5Y.js} +1 -1
- package/dist/assets/{ScanNetworkModal-Cjz6Frk3.js → ScanNetworkModal-CzpESdou.js} +1 -1
- package/dist/assets/{SceneMonitorEditor-ClVY678X.js → SceneMonitorEditor-oyJ6wM8D.js} +1 -1
- package/dist/assets/{Scenes-CeDiVzYd.js → Scenes-DdGSsxoN.js} +1 -1
- package/dist/assets/{Settings-BpYOVkge.js → Settings-pkejy-p8.js} +1 -1
- package/dist/assets/{Showroom-XhXg4zCE.js → Showroom-BPYNBg_-.js} +1 -1
- package/dist/assets/{StorageLocationsPanel-TaKlG_OL.js → StorageLocationsPanel-Bh9serlr.js} +1 -1
- package/dist/assets/{Terminal-Bb4L_QeH.js → Terminal-CA5TdsrG.js} +1 -1
- package/dist/assets/{Viewer-taY9peg7.js → Viewer-Drmg2Ejy.js} +1 -1
- package/dist/assets/{_virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-DlKUQx5r.js → _virtual_mf-localSharedImportMap___mfe_internal__admin_ui_host-D_KUeTsd.js} +1 -1
- package/dist/assets/{archive-fqvC5Brj.js → archive-qAgd4cmZ.js} +1 -1
- package/dist/assets/{authed-media-BvPEs5TB.js → authed-media-zct-j3cj.js} +1 -1
- package/dist/assets/{boxes-ClWpPtWg.js → boxes-B76KDVc3.js} +1 -1
- package/dist/assets/circle-slash-DqKy2VT5.js +1 -0
- package/dist/assets/{debounced-invalidate-By0Vn9ei.js → debounced-invalidate-D_2NBRHb.js} +1 -1
- package/dist/assets/dist-BZGaQ7Y7.js +1 -0
- package/dist/assets/dist-C2bPequg.js +349 -0
- package/dist/assets/{face-bbox-Cpje1INL.js → face-bbox-B8LQFqpz.js} +1 -1
- package/dist/assets/{hard-drive-download-DU8y4SBf.js → hard-drive-download-QwRO-K79.js} +1 -1
- package/dist/assets/{hostInit-Dr4RrHqp.js → hostInit-GlPGaf9F.js} +1 -1
- package/dist/assets/{index-Bxt1Fjnf.js → index-DMcMbxBl.js} +3 -3
- package/dist/assets/{layers-CRY7Jre0.js → layers-DpGMZn67.js} +1 -1
- package/dist/assets/{location-owned-usage-69VZ6M2D.js → location-owned-usage-DyThbZ3H.js} +1 -1
- package/dist/assets/{mf-entry-bootstrap-0-a997a261.js → mf-entry-bootstrap-0-466c9d23.js} +2 -2
- package/dist/assets/player-overlays-DBeLKlvr.js +1 -0
- package/dist/assets/remoteEntry-Blr1kesh.js +1 -0
- package/dist/assets/{send-DmQ6sJmy.js → send-Dj20pEAB.js} +1 -1
- package/dist/assets/{settings-2-D5fIb1dV.js → settings-2-DFFRVeal.js} +1 -1
- package/dist/assets/{square-check-big-BTFyRrw3.js → square-check-big-CrYM6cIR.js} +1 -1
- package/dist/assets/src-B2UA4y-L.js +349 -0
- package/dist/assets/src-Cr7Ldmwc.js +67 -0
- package/dist/assets/{use-scenes-feed-D6hN9ofn.js → use-scenes-feed-BnJkVAGn.js} +1 -1
- package/dist/assets/{use-stationary-objects-DyG-CkFU.js → use-stationary-objects-EvgA5taz.js} +1 -1
- package/dist/assets/useEventInvalidation-B6eXiCUA.js +1 -0
- package/dist/assets/{useNodeUrlSelection-Vqr54PE5.js → useNodeUrlSelection-CuL0_KpS.js} +1 -1
- package/dist/assets/user-round-Cs8qBz0D.js +1 -0
- package/dist/assets/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-Bvg142sG.js → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__admin_ui_host__remoteEntry-_hash_-CZO6_ULN.js} +2 -2
- package/dist/index.html +5 -5
- package/dist/server/addon.js +222 -15
- package/package.json +1 -1
- package/dist/assets/AiProfiles-DqnpZiM4.js +0 -3
- package/dist/assets/Integrations-DsPDj2q0.js +0 -1
- package/dist/assets/Notifications-jm5JkUGG.js +0 -1
- package/dist/assets/circle-slash-Nc-f9yJq.js +0 -1
- package/dist/assets/dist-B2jY4wyb.js +0 -1
- package/dist/assets/dist-DcOFqKuw.js +0 -349
- package/dist/assets/player-overlays-CjslyEYg.js +0 -1
- package/dist/assets/remoteEntry-CcCdSaNv.js +0 -1
- package/dist/assets/src-DPG5IJP-.js +0 -349
- package/dist/assets/src-yMwlDObw.js +0 -67
- package/dist/assets/useEventInvalidation-C1b8cBhp.js +0 -1
- package/dist/assets/user-round-DfBfVsLc.js +0 -1
package/dist/server/addon.js
CHANGED
|
@@ -14537,18 +14537,30 @@ var LlmErrorCodeSchema = _enum([
|
|
|
14537
14537
|
"budget-exceeded",
|
|
14538
14538
|
"adapter-error"
|
|
14539
14539
|
]);
|
|
14540
|
-
var
|
|
14540
|
+
var LlmGenerateOkSchema = object({
|
|
14541
14541
|
ok: literal(true),
|
|
14542
14542
|
text: string(),
|
|
14543
14543
|
model: string(),
|
|
14544
14544
|
usage: LlmUsageSchema,
|
|
14545
14545
|
truncated: boolean(),
|
|
14546
14546
|
latencyMs: number()
|
|
14547
|
-
})
|
|
14547
|
+
});
|
|
14548
|
+
/**
|
|
14549
|
+
* WHO refused, on a `refusal`. `guardrail` = a safety filter in front of the
|
|
14550
|
+
* model rejected the request before it answered (Apple Foundation Models
|
|
14551
|
+
* refuses surveillance-framed prompts in 0.1 s); `model` = the model itself
|
|
14552
|
+
* declined. They are different faults: a guardrail refusal is a property of
|
|
14553
|
+
* the BACKEND, so the provider falls back to the next profile; a model refusal
|
|
14554
|
+
* is an answer. Absent on every other code, and on a refusal a wire cannot
|
|
14555
|
+
* attribute.
|
|
14556
|
+
*/
|
|
14557
|
+
var LlmRefusalSourceSchema = _enum(["guardrail", "model"]);
|
|
14558
|
+
var LlmGenerateResultSchema = discriminatedUnion("ok", [LlmGenerateOkSchema, object({
|
|
14548
14559
|
ok: literal(false),
|
|
14549
14560
|
code: LlmErrorCodeSchema,
|
|
14550
14561
|
message: string(),
|
|
14551
|
-
retryAfterMs: number().optional()
|
|
14562
|
+
retryAfterMs: number().optional(),
|
|
14563
|
+
refusalSource: LlmRefusalSourceSchema.optional()
|
|
14552
14564
|
})]);
|
|
14553
14565
|
/**
|
|
14554
14566
|
* `Uint8Array` is the sanctioned binary convention — superjson + the UDS
|
|
@@ -14778,12 +14790,78 @@ var LlmRuntimeDiskUsageSchema = object({
|
|
|
14778
14790
|
modelsBytes: number(),
|
|
14779
14791
|
freeBytes: number().optional()
|
|
14780
14792
|
});
|
|
14781
|
-
|
|
14793
|
+
var LlmRuntimeCompleteInputSchema = LlmGenerateBaseInputSchema.extend({
|
|
14782
14794
|
images: array(LlmImageSchema).optional(),
|
|
14783
14795
|
runtime: ManagedRuntimeConfigSchema,
|
|
14784
14796
|
/** The managed profile's timeout, threaded by the hub provider. */
|
|
14785
14797
|
timeoutMs: number().int().positive().optional()
|
|
14786
|
-
})
|
|
14798
|
+
});
|
|
14799
|
+
/**
|
|
14800
|
+
* Why Apple Foundation Models cannot run on a node that has it in principle.
|
|
14801
|
+
* The first three are Apple's own `UnavailableReason`s, verbatim; the rest are
|
|
14802
|
+
* ours: the OS predates the framework (macOS < 26), the helper binary is not
|
|
14803
|
+
* in the installed addon, or it crashed past the respawn bound.
|
|
14804
|
+
*/
|
|
14805
|
+
var AppleFmUnavailableReasonSchema = _enum([
|
|
14806
|
+
"deviceNotEligible",
|
|
14807
|
+
"appleIntelligenceNotEnabled",
|
|
14808
|
+
"modelNotReady",
|
|
14809
|
+
"osTooOld",
|
|
14810
|
+
"helperMissing",
|
|
14811
|
+
"helperCrashed"
|
|
14812
|
+
]);
|
|
14813
|
+
/**
|
|
14814
|
+
* Apple Foundation Models on ONE node — four states, never a boolean (D315).
|
|
14815
|
+
*
|
|
14816
|
+
* - `available` — the helper probed it; what it CAN do is reported
|
|
14817
|
+
* here (`imageInput`, `contextSize`, languages),
|
|
14818
|
+
* never typed by an operator.
|
|
14819
|
+
* - `unavailable` — a known absence, with the reason to act on.
|
|
14820
|
+
* - `unsupported-platform` — not a Mac; there is nothing to enable.
|
|
14821
|
+
* - `unknown` — the probe did not answer (not yet run, timed
|
|
14822
|
+
* out, helper crashed mid-probe). A failed
|
|
14823
|
+
* measurement is NEVER `unavailable` (D393).
|
|
14824
|
+
*/
|
|
14825
|
+
var AppleFmAvailabilitySchema = discriminatedUnion("state", [
|
|
14826
|
+
object({
|
|
14827
|
+
state: literal("available"),
|
|
14828
|
+
osVersion: string(),
|
|
14829
|
+
/** Tokens, as the framework reports it. Read at runtime, never assumed. */
|
|
14830
|
+
contextSize: number().int().positive(),
|
|
14831
|
+
/** BCP-47-ish tags (`it-IT`) of the languages the model supports. */
|
|
14832
|
+
languages: array(string()),
|
|
14833
|
+
/** Whether prompts may carry images. `false` on a macOS 26 build. */
|
|
14834
|
+
imageInput: boolean()
|
|
14835
|
+
}),
|
|
14836
|
+
object({
|
|
14837
|
+
state: literal("unavailable"),
|
|
14838
|
+
reason: AppleFmUnavailableReasonSchema,
|
|
14839
|
+
osVersion: string().nullable(),
|
|
14840
|
+
detail: string()
|
|
14841
|
+
}),
|
|
14842
|
+
object({
|
|
14843
|
+
state: literal("unsupported-platform"),
|
|
14844
|
+
platform: string()
|
|
14845
|
+
}),
|
|
14846
|
+
object({
|
|
14847
|
+
state: literal("unknown"),
|
|
14848
|
+
error: string()
|
|
14849
|
+
})
|
|
14850
|
+
]);
|
|
14851
|
+
/**
|
|
14852
|
+
* A generation on the node's Apple Foundation Models helper. A separate verb
|
|
14853
|
+
* from `complete`, whose `runtime` is a llama.cpp config: overloading it would
|
|
14854
|
+
* drag a GGUF model reference into a backend that has none. `images` is part
|
|
14855
|
+
* of the contract so vision needs no cap change later; a node whose model has
|
|
14856
|
+
* no image input REFUSES them (`unavailable`), never drops them.
|
|
14857
|
+
*/
|
|
14858
|
+
var LlmRuntimeAppleCompleteInputSchema = LlmGenerateBaseInputSchema.extend({
|
|
14859
|
+
images: array(LlmImageSchema).optional(),
|
|
14860
|
+
/** The profile's timeout, threaded by the hub provider. */
|
|
14861
|
+
timeoutMs: number().int().positive().optional()
|
|
14862
|
+
});
|
|
14863
|
+
var LlmRuntimeCancelInputSchema = object({ requestId: string() });
|
|
14864
|
+
method(LlmRuntimeCompleteInputSchema, LlmGenerateResultSchema, {
|
|
14787
14865
|
kind: "mutation",
|
|
14788
14866
|
auth: "admin",
|
|
14789
14867
|
timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
|
|
@@ -14801,7 +14879,14 @@ method(LlmGenerateBaseInputSchema.extend({
|
|
|
14801
14879
|
}), method(object({ file: string() }), _void(), {
|
|
14802
14880
|
kind: "mutation",
|
|
14803
14881
|
auth: "admin"
|
|
14804
|
-
}), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" })
|
|
14882
|
+
}), method(object({}), array(LlmNodeModelSchema), { auth: "admin" }), method(object({}), LlmRuntimeDiskUsageSchema, { auth: "admin" }), method(LlmRuntimeCancelInputSchema, _void(), {
|
|
14883
|
+
kind: "mutation",
|
|
14884
|
+
auth: "admin"
|
|
14885
|
+
}), method(object({}), AppleFmAvailabilitySchema, { auth: "admin" }), method(LlmRuntimeAppleCompleteInputSchema, LlmGenerateResultSchema, {
|
|
14886
|
+
kind: "mutation",
|
|
14887
|
+
auth: "admin",
|
|
14888
|
+
timeoutMs: AI_CAP_TRANSPORT_TIMEOUT_MS
|
|
14889
|
+
});
|
|
14805
14890
|
/**
|
|
14806
14891
|
* `llm` — consumer-facing LLM surface (spec §1-§3). Collection-mode: array
|
|
14807
14892
|
* methods concat-fan across providers; single-row methods route to ONE
|
|
@@ -14818,7 +14903,8 @@ var LlmProfileKindSchema = _enum([
|
|
|
14818
14903
|
"openai",
|
|
14819
14904
|
"anthropic",
|
|
14820
14905
|
"google",
|
|
14821
|
-
"managed-local"
|
|
14906
|
+
"managed-local",
|
|
14907
|
+
"apple-foundation"
|
|
14822
14908
|
]);
|
|
14823
14909
|
var LlmProfileSchema = object({
|
|
14824
14910
|
id: string(),
|
|
@@ -14876,7 +14962,14 @@ var LlmProfileSchema = object({
|
|
|
14876
14962
|
toolsEnabled: boolean().default(false),
|
|
14877
14963
|
extraHeaders: record(string(), string()).optional(),
|
|
14878
14964
|
/** kind === 'managed-local' only (spec §4). */
|
|
14879
|
-
runtime: ManagedRuntimeConfigSchema.optional()
|
|
14965
|
+
runtime: ManagedRuntimeConfigSchema.optional(),
|
|
14966
|
+
/**
|
|
14967
|
+
* kind === 'apple-foundation' only: WHERE it runs — the only thing there is
|
|
14968
|
+
* to configure (no key, no URL, no download; `model` is `apple-system`).
|
|
14969
|
+
* `supportsVision` on such a row is stamped by the provider from the node's
|
|
14970
|
+
* reported `imageInput`, never taken from the operator (D62).
|
|
14971
|
+
*/
|
|
14972
|
+
appleFoundation: object({ nodeId: string() }).optional()
|
|
14880
14973
|
});
|
|
14881
14974
|
/** ConfigUISchema tree passed through untyped on the wire (the
|
|
14882
14975
|
* notification-output `ConfigSchemaPassthrough` precedent at
|
|
@@ -14958,7 +15051,9 @@ var LlmRuntimeNodeSchema = object({
|
|
|
14958
15051
|
reachable: boolean(),
|
|
14959
15052
|
status: LlmRuntimeStatusSchema.optional(),
|
|
14960
15053
|
disk: LlmRuntimeDiskUsageSchema.optional(),
|
|
14961
|
-
error: string().optional()
|
|
15054
|
+
error: string().optional(),
|
|
15055
|
+
/** Absent = the node did not answer the question (render as unknown). */
|
|
15056
|
+
apple: AppleFmAvailabilitySchema.optional()
|
|
14962
15057
|
});
|
|
14963
15058
|
var GenerateVisionInputSchema = LlmGenerateBaseInputSchema.extend({ images: array(LlmImageSchema).min(1) });
|
|
14964
15059
|
var ProfileRefInputSchema = object({
|
|
@@ -17937,9 +18032,29 @@ var NcTestResultSchema = object({
|
|
|
17937
18032
|
className: string().optional(),
|
|
17938
18033
|
label: string().optional()
|
|
17939
18034
|
});
|
|
17940
|
-
/** The
|
|
17941
|
-
*
|
|
18035
|
+
/** The rule kinds, as data. `NcRuleKind` in `notification/rule-kinds.ts` is the
|
|
18036
|
+
* same union; the template-vars spec pins the two together. `mixed` is DERIVED
|
|
18037
|
+
* (a stored system rule whose kinds span families, D637) and never authored. */
|
|
17942
18038
|
var NcRuleKindSchema = _enum([
|
|
18039
|
+
"detection",
|
|
18040
|
+
"sensor",
|
|
18041
|
+
"occupancy",
|
|
18042
|
+
"sound",
|
|
18043
|
+
"device-events",
|
|
18044
|
+
"system",
|
|
18045
|
+
"alarm",
|
|
18046
|
+
"mixed"
|
|
18047
|
+
]);
|
|
18048
|
+
/**
|
|
18049
|
+
* The kinds a SERVED template-variable descriptor may name: the five that
|
|
18050
|
+
* existed before D637, frozen. `getTemplateCatalog` ships `kinds` to every
|
|
18051
|
+
* installed viewer, and a viewer at `@camstack/types` 1.2.25x parses them with a
|
|
18052
|
+
* strict five-member enum — one `device-events` in one descriptor fails the
|
|
18053
|
+
* whole catalog parse. So the WIRE says `system`, and the MATCH widens it:
|
|
18054
|
+
* `templateVarKindApplies` reads a `system` descriptor as applying to every
|
|
18055
|
+
* system rule kind (`device-events`, `system`, `alarm`, `mixed`).
|
|
18056
|
+
*/
|
|
18057
|
+
var NcTemplateVarKindSchema = _enum([
|
|
17943
18058
|
"detection",
|
|
17944
18059
|
"sensor",
|
|
17945
18060
|
"occupancy",
|
|
@@ -17977,7 +18092,7 @@ var NcTemplateVarGroupSchema = _enum([
|
|
|
17977
18092
|
*
|
|
17978
18093
|
* `families` / `fields` / `kinds` / `deliveries` / `systemEventKinds` say WHERE
|
|
17979
18094
|
* it has a value; absent = no restriction on that axis. `systemEventKinds` is
|
|
17980
|
-
* read only for a
|
|
18095
|
+
* read only for a system-event rule (any family, or `mixed`). `dynamic` declares a FAMILY of names
|
|
17981
18096
|
* (`count_<class>`): the descriptor's `name` is the example member.
|
|
17982
18097
|
*/
|
|
17983
18098
|
var NcTemplateVarDescriptorSchema = object({
|
|
@@ -17988,7 +18103,7 @@ var NcTemplateVarDescriptorSchema = object({
|
|
|
17988
18103
|
group: NcTemplateVarGroupSchema,
|
|
17989
18104
|
families: array(NcTemplateFamilySchema).min(1),
|
|
17990
18105
|
fields: array(NcTemplateFieldSchema).optional(),
|
|
17991
|
-
kinds: array(
|
|
18106
|
+
kinds: array(NcTemplateVarKindSchema).optional(),
|
|
17992
18107
|
deliveries: array(NcDeliverySchema).optional(),
|
|
17993
18108
|
systemEventKinds: array(NcSystemEventKindSchema).optional(),
|
|
17994
18109
|
dynamic: object({
|
|
@@ -29100,7 +29215,30 @@ var RenameNodeResultSchema = object({
|
|
|
29100
29215
|
nodeId: string(),
|
|
29101
29216
|
name: string()
|
|
29102
29217
|
});
|
|
29103
|
-
|
|
29218
|
+
/**
|
|
29219
|
+
* The cheap node list. A consumer's rule for a STORED node id (a rule's
|
|
29220
|
+
* `nodeIds`) that is missing from `nodes`, whatever `complete` says: render it
|
|
29221
|
+
* as a removable chip labelled unknown, never drop it (D49). Even a complete
|
|
29222
|
+
* list omits a node that joined and left between two history captures, so a
|
|
29223
|
+
* missing id means "not known to the hub", never "removed". Only the operator
|
|
29224
|
+
* removes it.
|
|
29225
|
+
*
|
|
29226
|
+
* `complete` changes only the WORDING: `false` = no history read has ever
|
|
29227
|
+
* answered, so the list may be missing offline nodes the hub does know (D315).
|
|
29228
|
+
*
|
|
29229
|
+
* `name` is the history row's name (≤ 30 s behind a rename), or the id when
|
|
29230
|
+
* the history has none.
|
|
29231
|
+
*/
|
|
29232
|
+
var NodeDirectorySchema = object({
|
|
29233
|
+
nodes: array(object({
|
|
29234
|
+
id: string(),
|
|
29235
|
+
name: string(),
|
|
29236
|
+
isHub: boolean(),
|
|
29237
|
+
isOnline: boolean()
|
|
29238
|
+
})).readonly(),
|
|
29239
|
+
complete: boolean()
|
|
29240
|
+
});
|
|
29241
|
+
method(_void(), array(TopologyNodeSchema).readonly(), { auth: "admin" }), method(_void(), NodeDirectorySchema, { auth: "admin" }), method(NodeAddonInputSchema, SuccessSchema, {
|
|
29104
29242
|
kind: "mutation",
|
|
29105
29243
|
auth: "admin"
|
|
29106
29244
|
}), method(NodeAddonInputSchema, SuccessSchema, {
|
|
@@ -37529,12 +37667,30 @@ Object.freeze({
|
|
|
37529
37667
|
addonId: null,
|
|
37530
37668
|
access: "create"
|
|
37531
37669
|
},
|
|
37670
|
+
"llmRuntime.appleAvailability": {
|
|
37671
|
+
capName: "llm-runtime",
|
|
37672
|
+
capScope: "system",
|
|
37673
|
+
addonId: null,
|
|
37674
|
+
access: "view"
|
|
37675
|
+
},
|
|
37676
|
+
"llmRuntime.cancel": {
|
|
37677
|
+
capName: "llm-runtime",
|
|
37678
|
+
capScope: "system",
|
|
37679
|
+
addonId: null,
|
|
37680
|
+
access: "create"
|
|
37681
|
+
},
|
|
37532
37682
|
"llmRuntime.complete": {
|
|
37533
37683
|
capName: "llm-runtime",
|
|
37534
37684
|
capScope: "system",
|
|
37535
37685
|
addonId: null,
|
|
37536
37686
|
access: "create"
|
|
37537
37687
|
},
|
|
37688
|
+
"llmRuntime.completeApple": {
|
|
37689
|
+
capName: "llm-runtime",
|
|
37690
|
+
capScope: "system",
|
|
37691
|
+
addonId: null,
|
|
37692
|
+
access: "create"
|
|
37693
|
+
},
|
|
37538
37694
|
"llmRuntime.deleteModel": {
|
|
37539
37695
|
capName: "llm-runtime",
|
|
37540
37696
|
capScope: "system",
|
|
@@ -38207,6 +38363,12 @@ Object.freeze({
|
|
|
38207
38363
|
addonId: null,
|
|
38208
38364
|
access: "create"
|
|
38209
38365
|
},
|
|
38366
|
+
"nodes.directory": {
|
|
38367
|
+
capName: "nodes",
|
|
38368
|
+
capScope: "system",
|
|
38369
|
+
addonId: null,
|
|
38370
|
+
access: "view"
|
|
38371
|
+
},
|
|
38210
38372
|
"nodes.executeQuery": {
|
|
38211
38373
|
capName: "nodes",
|
|
38212
38374
|
capScope: "system",
|
|
@@ -43971,6 +44133,51 @@ var NC_AUDIO_DEFAULTS = {
|
|
|
43971
44133
|
samplingSeconds: 10
|
|
43972
44134
|
};
|
|
43973
44135
|
new Set(["devices", "classes"]);
|
|
44136
|
+
/** Every filter, for the callers that must cover all four (guards, tests). */
|
|
44137
|
+
var NC_SYSTEM_EVENT_FILTER_KEYS = [
|
|
44138
|
+
"deviceIds",
|
|
44139
|
+
"deviceTypes",
|
|
44140
|
+
"nodeIds",
|
|
44141
|
+
"packageNames"
|
|
44142
|
+
];
|
|
44143
|
+
new Map(Object.entries({
|
|
44144
|
+
"device-online": "device-events",
|
|
44145
|
+
"device-offline": "device-events",
|
|
44146
|
+
"device-disabled": "device-events",
|
|
44147
|
+
"device-enabled": "device-events",
|
|
44148
|
+
"device-battery-low": "device-events",
|
|
44149
|
+
"device-battery-normal": "device-events",
|
|
44150
|
+
"device-consumable-low": "device-events",
|
|
44151
|
+
"device-consumable-normal": "device-events",
|
|
44152
|
+
"stream-online": "device-events",
|
|
44153
|
+
"stream-offline": "device-events",
|
|
44154
|
+
"detection-blind": "device-events",
|
|
44155
|
+
"node-online": "system",
|
|
44156
|
+
"node-offline": "system",
|
|
44157
|
+
"node-inference-unavailable": "system",
|
|
44158
|
+
"addon-crash-loop": "system",
|
|
44159
|
+
"addon-update-available": "system",
|
|
44160
|
+
"addon-updated": "system",
|
|
44161
|
+
"server-update-available": "system",
|
|
44162
|
+
"server-updated": "system",
|
|
44163
|
+
"wrapper-update-available": "system",
|
|
44164
|
+
"backup-completed": "system",
|
|
44165
|
+
"export-completed": "system",
|
|
44166
|
+
"alarm-triggered": "alarm",
|
|
44167
|
+
"alarm-armed": "alarm",
|
|
44168
|
+
"alarm-disarmed": "alarm",
|
|
44169
|
+
"alarm-arming": "alarm",
|
|
44170
|
+
"alarm-arm-refused": "alarm",
|
|
44171
|
+
"alarm-pending": "alarm",
|
|
44172
|
+
"alarm-rearmed": "alarm",
|
|
44173
|
+
"alarm-sensor-bypass": "alarm",
|
|
44174
|
+
"alarm-check-failed": "alarm",
|
|
44175
|
+
"camera-online": null,
|
|
44176
|
+
"camera-offline": null,
|
|
44177
|
+
"camera-disabled": null,
|
|
44178
|
+
"camera-enabled": null
|
|
44179
|
+
}));
|
|
44180
|
+
[...NC_SYSTEM_EVENT_FILTER_KEYS];
|
|
43974
44181
|
NC_AUDIO_DEFAULTS.hitPercent, NC_AUDIO_DEFAULTS.samplingSeconds;
|
|
43975
44182
|
var RULE_BODY_ONLY = ["body"];
|
|
43976
44183
|
var RULE_TEXT = ["title", "body"];
|
|
@@ -44501,7 +44708,7 @@ var AdminUIAddon = class extends BaseAddon {
|
|
|
44501
44708
|
capability: adminUiCapability,
|
|
44502
44709
|
provider: {
|
|
44503
44710
|
getStaticDir: async () => ({ staticDir: resolveAdminUiDistDir() }),
|
|
44504
|
-
getVersion: async () => ({ version: "1.2.
|
|
44711
|
+
getVersion: async () => ({ version: "1.2.266" })
|
|
44505
44712
|
}
|
|
44506
44713
|
}];
|
|
44507
44714
|
}
|
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{W as d,Z as f,_t as p,at as m,ct as h,st as g,vt as _}from"./player-overlays-CjslyEYg.js";import{At as v,Cl as y,Dc as b,Du as x,Ft as S,It as C,Jl as w,Kt as T,Ll as E,Nt as D,Pt as O,Qt as k,Rt as A,Sl as ee,Tl as j,Yl as te,Zc as M,Zt as N,_ as ne,au as P,ct as F,cu as I,dl as L,du as R,ii as z,in as B,jt as V,kt as H,lt as U,rn as re,tn as W,ul as G}from"./src-yMwlDObw.js";import{t as ie}from"./boxes-ClWpPtWg.js";import{t as ae}from"./send-DmQ6sJmy.js";import{vt as K}from"./src-DPG5IJP-.js";import{n as q}from"./index-Bxt1Fjnf.js";import{t as J}from"./AdminPage-CiKtOLQm.js";import{t as oe}from"./AdminTabs-BGbLei2R.js";var se=_(`message-square-plus`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}],[`path`,{d:`M12 8v6`,key:`1ib9pf`}],[`path`,{d:`M9 11h6`,key:`1fldmi`}]]);n();var ce=[`llm`,`listProfiles`],le=[`llm`,`listProfileKinds`],ue=[`llm`,`getDefaults`],de=[`llm`,`listRuntimeNodes`],fe=[`llm`,`listModelCatalog`],pe=[`llm`,`getUsage`],me=[{purpose:`vision`,visionOnly:!0},{purpose:`text`,visionOnly:!1}],he=new Map(Object.entries({openai:R,anthropic:R,google:R,"openai-compatible":ee,"managed-local":I}));function ge(e){return he.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 _e(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,extraArgs:xe(e.runtime?.extraArgs??[])}}var ve=[`f32`,`f16`,`q8_0`,`q5_1`,`q5_0`,`q4_1`,`q4_0`];function ye(e){return typeof e==`string`&&ve.includes(e)?e:void 0}function be(e){let t=[],n=``,r=null;for(let i of e){if(r!==null){i===r?r=null:n+=i;continue}if(i===`"`||i===`'`){r=i;continue}if(/\s/.test(i)){n!==``&&t.push(n),n=``;continue}n+=i}return n!==``&&t.push(n),t}function xe(e){return e.map(e=>/\s/.test(e)?`"${e}"`:e).join(` `)}var Se=[`--jinja`,`--cont-batching`];function Ce(e,t,n){let r=X(e.threads),i=X(e.batchSize),a=X(e.ubatchSize),o=ye(e.cacheTypeK),s=ye(e.cacheTypeV);return{nodeId:t,engine:`llama-cpp`,model:n,extraArgs:[...be(Y(e.extraArgs)??``)],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 we(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)??K.totalMs,connectTimeoutMs:X(r.connectTimeoutMs)??K.connectMs,firstTokenTimeoutMs:X(r.firstTokenTimeoutMs)??K.firstTokenMs,idleTimeoutMs:X(r.idleTimeoutMs)??K.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.modelId,runtime:Ce(r,i.nodeId,i.model)}}}function Te(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}))}var Ee=2e3;function Q(e){return`${(e/1e9).toFixed(2)} GB`}function De(e){return e===null?``:e.model.kind===`catalog`?`catalog:${e.model.catalogId}`:e.model.kind===`path`?`node:${e.modelId}`:`custom`}function Oe({nodeId:e,value:t,onChange:n}){let{t:o}=q(),u=m(),[d,f]=s(``),[p,h]=s(null),[g,_]=s(!1),v=a({queryKey:fe,queryFn:()=>u.trpcClient.llm.listModelCatalog.query({})}),y=a({queryKey:[`llm`,`listNodeModels`,e],queryFn:()=>u.trpcClient.llm.listNodeModels.query({nodeId:e})}),b=c({mutationFn:e=>u.trpcClient.llm.resolveModelRef.mutate(e),onSuccess:e=>{h(e),_(!1),e.ok&&n({model:e.model,modelId:e.label,supportsVision:e.purpose===`vision`})}}),x=c({mutationFn:t=>u.trpcClient.llm.installModel.mutate({nodeId:e,model:t}),onSuccess:()=>{_(!0),y.refetch()}}),S=a({queryKey:de,enabled:x.isPending,refetchInterval:x.isPending?Ee:!1,queryFn:()=>u.trpcClient.llm.listRuntimeNodes.query({})}).data?.find(t=>t.nodeId===e)?.status?.download,C=i(()=>{let t=(v.data??[]).map(e=>({value:`catalog:${e.id}`,label:`${e.label} · ${e.quantization} · ${Q(e.sizeBytes)}`})),n=(y.data??[]).filter(e=>e.catalogId===void 0&&e.path!==void 0).map(t=>({value:`node:${t.file}`,label:o(`ai.onNode`,`{{file}} · {{size}} · on {{node}}`,{file:t.file,size:Q(t.sizeBytes),node:e})})),r=p?.ok===!0?[{value:`custom`,label:`${p.label} · ${Q(p.totalBytes)}`}]:[];return[{value:``,label:o(`ai.selectModel`,`Select a model…`)},...t,...n,...r]},[v.data,y.data,p,e,o]),w=e=>{if(e===``){n(null);return}if(e===`custom`){if(p?.ok!==!0)return;n({model:p.model,modelId:p.label,supportsVision:p.purpose===`vision`});return}if(e.startsWith(`catalog:`)){let t=e.slice(8),r=v.data?.find(e=>e.id===t);n({model:{kind:`catalog`,catalogId:t},modelId:t,supportsVision:r?.purpose===`vision`});return}let t=e.slice(5),r=y.data?.find(e=>e.file===t);r?.path!==void 0&&n({model:{kind:`path`,path:r.path},modelId:t,supportsVision:!1})},T=e=>{d.trim()!==``&&b.mutate({ref:d.trim(),...e===void 0?{}:{maxBytes:e}})};return r(`div`,{className:`space-y-2`,children:[r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-model`,children:o(`ai.model`,`Model`)}),l(re,{id:`ai-model`,value:De(t),options:C,onChange:e=>w(e.target.value)})]}),r(`div`,{className:`rounded-md border border-border bg-surface-subtle px-3 py-2.5`,children:[l(`div`,{className:`mb-1 text-[11px] font-medium text-foreground`,children:o(`ai.hfTitle`,`Add a model from Hugging Face`)}),l(`p`,{className:`mb-2 text-[10px] leading-relaxed text-foreground-subtle`,children:o(`ai.hfHint`,`Paste a GGUF file URL, or type org/repo — add :QUANT (e.g. unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M) when the repo publishes more than one quantization.`)}),r(`div`,{className:`flex gap-2`,children:[l(A,{value:d,onChange:e=>f(e.target.value),placeholder:`unsloth/Qwen3.6-35B-A3B-GGUF:UD-Q4_K_M`,onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),T())}}),r(B,{size:`sm`,variant:`secondary`,type:`button`,disabled:d.trim()===``||b.isPending,onClick:()=>T(),children:[b.isPending?l(E,{className:`h-3.5 w-3.5 animate-spin`}):l(L,{className:`h-3.5 w-3.5`}),o(`ai.hfCheck`,`Check`)]})]}),b.isError&&l(`p`,{className:`mt-2 text-[11px] text-danger`,children:b.error instanceof Error?b.error.message:o(`common.error`,`Error`)}),p?.ok===!1&&r(`div`,{className:`mt-2 rounded-md border border-danger/40 bg-danger/10 px-2.5 py-2`,children:[l(`p`,{className:`text-[11px] text-danger`,children:p.message}),p.candidates!==void 0&&p.candidates.length>0&&l(`div`,{className:`mt-1.5 flex flex-wrap gap-1`,children:p.candidates.map(e=>l(`button`,{type:`button`,className:`rounded border border-border bg-surface px-1.5 py-0.5 text-[10px] text-foreground hover:border-primary/50`,onClick:()=>{let t=`${d.trim().split(`:`)[0]??``}:${e}`;f(t),b.mutate({ref:t})},children:e},e))}),p.requiredBytes!==void 0&&l(B,{size:`sm`,variant:`secondary`,type:`button`,className:`mt-2`,onClick:()=>T(p.requiredBytes),children:o(`ai.hfOverride`,`Install anyway ({{size}})`,{size:Q(p.requiredBytes)})})]}),p?.ok===!0&&r(`div`,{className:`mt-2 rounded-md border border-border bg-surface px-2.5 py-2`,children:[r(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:[l(`span`,{className:`text-[11px] font-medium text-foreground`,children:p.label}),l(N,{variant:p.purpose===`vision`?`info`:`default`,children:p.purpose}),l(N,{variant:`default`,children:Q(p.totalBytes)})]}),p.extraFilenames.length>0&&l(`p`,{className:`mt-1 text-[10px] text-foreground-subtle`,children:o(`ai.hfExtras`,`Also downloads: {{files}}`,{files:p.extraFilenames.join(`, `)})}),r(`div`,{className:`mt-2 flex items-center gap-2`,children:[r(B,{size:`sm`,type:`button`,disabled:x.isPending||g,onClick:()=>x.mutate(p.model),children:[x.isPending?l(E,{className:`h-3.5 w-3.5 animate-spin`}):l(P,{className:`h-3.5 w-3.5`}),g?o(`ai.hfInstalled`,`Downloaded`):o(`ai.hfInstall`,`Download to {{node}}`,{node:e})]}),S!==void 0&&l(`span`,{className:`text-[10px] text-foreground-subtle`,children:S.phase===`verifying`?o(`ai.hfVerifying`,`verifying {{file}}…`,{file:S.file}):o(`ai.hfDownloading`,`{{file}} ({{index}}/{{count}}) — {{done}}{{total}}`,{file:S.file,index:S.fileIndex,count:S.fileCount,done:Q(S.downloadedBytes),total:S.totalBytes===void 0?``:` / ${Q(S.totalBytes)}`})})]}),x.isError&&l(`p`,{className:`mt-1.5 text-[11px] text-danger`,children:x.error instanceof Error?x.error.message:o(`common.error`,`Error`)})]})]})]})}n();function ke({kind:e,className:t}){let n=ge(e.kind);return n===null?l(`span`,{className:t,children:e.icon}):l(n,{className:t})}function Ae({kinds:e,onPick:t,onCancel:n}){let{t:a}=q(),o=i(()=>Te(e),[e]);return l(H,{open:!0,onOpenChange:e=>!e&&n(),children:r(V,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(O,{children:l(S,{children:a(`ai.chooseKind`,`Choose a profile type`)})}),r(v,{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(ke,{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(B,{size:`sm`,variant:`secondary`,type:`button`,onClick:n,children:a(`common.cancel`,`Cancel`)})})]})})}function je({kind:e,existing:t,onSave:n,onCancel:a,saving:c,error:u}){let{t:d}=q(),f=e.kind===`managed-local`,[p,m]=s(t?.name??e.label),[h,g]=s(()=>t===null?{}:_e(t)),[_,y]=s(t?.runtime?.nodeId??`hub`),[b,x]=s(()=>t?.runtime===void 0?null:{model:t.runtime.model,modelId:t.model,supportsVision:t.supportsVision}),C=i(()=>be(Y(h.extraArgs)??``),[h.extraArgs]),w=()=>{if(!f){n(we(e.kind,p,t,h));return}b!==null&&n(we(e.kind,p,t,h,{nodeId:_,model:b.model,modelId:b.modelId,supportsVision:b.supportsVision}))},k=c||p.trim()===``||f&&b===null;return l(H,{open:!0,onOpenChange:e=>!e&&a(),children:r(V,{width:`lg`,placement:`sheet-on-mobile`,scroll:`body`,children:[l(O,{children:r(S,{className:`flex items-center gap-2`,children:[l(ke,{kind:e,className:`h-4 w-4 text-foreground-subtle`}),t===null?d(`ai.newProfile`,`New {{kind}} profile`,{kind:e.label}):d(`ai.editProfile`,`Edit {{name}}`,{name:t.name})]})}),r(v,{className:`space-y-3 pr-1`,children:[u!==null&&l(`div`,{className:`rounded-md border border-danger/40 bg-danger/10 px-3 py-2 text-xs text-danger`,children:u}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-profile-name`,children:d(`ai.name`,`Name`)}),l(A,{id:`ai-profile-name`,value:p,onChange:e=>m(e.target.value),placeholder:e.label})]}),f&&r(o,{children:[l(ne,{selectedNodeId:_,onSelect:y,label:d(`ai.runtimeNode`,`Runtime node`),alwaysShow:!0}),l(Oe,{nodeId:_,value:b,onChange:x}),r(`div`,{children:[l(`label`,{className:`mb-1 block text-[11px] font-medium text-foreground`,htmlFor:`ai-extra-args`,children:d(`ai.extraArgs`,`Additional llama-server arguments`)}),l(A,{id:`ai-extra-args`,value:Y(h.extraArgs)??``,onChange:e=>g({...h,extraArgs:e.target.value}),placeholder:Se.join(` `)}),C.length>0&&l(`div`,{className:`mt-1 flex flex-wrap gap-1`,children:C.map((e,t)=>l(N,{variant:`default`,children:e},`${e}-${String(t)}`))}),l(`p`,{className:`mt-1 text-[10px] leading-relaxed text-foreground-subtle`,children:d(`ai.extraArgsHint`,`Flags this form does not already own. Vision models generally need --jinja; some language-only models do not like it. Context size, GPU layers, parallel slots, flash attention and the KV-cache types are set in the fields below — repeating one here is rejected at start.`)})]})]}),l(T,{schema:e.configSchema,values:h,onChange:g}),t!==null&&l(`p`,{className:`text-[10px] text-foreground-subtle`,children:d(`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:[f&&b===null&&l(N,{variant:`warning`,children:d(`ai.pickModelFirst`,`pick a model`)}),l(B,{size:`sm`,variant:`secondary`,type:`button`,onClick:a,children:d(`common.cancel`,`Cancel`)}),r(B,{size:`sm`,type:`button`,disabled:k,onClick:w,children:[c&&l(E,{className:`h-3.5 w-3.5 animate-spin`}),t===null?d(`ai.createProfile`,`Create profile`):d(`ai.saveChanges`,`Save changes`)]})]})]})})}n();function Me(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(ke,{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(N,{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(N,{variant:`default`,children:e.runtime.nodeId})},{key:`enabled`,header:e.t(`ai.colOn`,`On`),align:`center`,nowrap:!0,render:t=>l(C,{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(B,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onTest(t),title:e.t(`ai.test`,`Test`),children:e.testingId===t.id?l(E,{className:`h-3.5 w-3.5 animate-spin`}):l(ae,{className:`h-3.5 w-3.5`})}),l(B,{size:`sm`,variant:`ghost`,type:`button`,disabled:!e.kindByName.has(t.kind),onClick:()=>e.onEdit(t),title:e.t(`common.edit`,`Edit`),children:l(j,{className:`h-3.5 w-3.5`})}),l(B,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>e.onDelete(t),title:e.t(`common.delete`,`Delete`),children:l(g,{className:`h-3.5 w-3.5 text-danger`})})]})}]}function Ne(){let{t:e}=q(),t=m(),[n,o]=s({mode:`closed`}),[u,d]=s(null),[f,p]=s(null),h=a({queryKey:ce,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),g=a({queryKey:le,queryFn:async()=>(await t.trpcClient.llm.listProfileKinds.query({})).map(e=>({...e,configSchema:e.configSchema}))}),_=()=>{h.refetch()},v=c({mutationFn:e=>t.trpcClient.llm.upsertProfile.mutate({profile:e}),onSuccess:()=>{o({mode:`closed`}),p(null),_()},onError:t=>p(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:_}),x=c({mutationFn:e=>t.trpcClient.llm.testProfile.mutate({addonId:e.addonId,profileId:e.id}),onSuccess:(e,t)=>d({id:t.id,ok:e.ok,text:e.ok?`${e.text} (${String(e.usage.outputTokens)} tok, ${String(e.latencyMs)}ms)`:`${e.code}: ${e.message}`})}),S=h.data??[],C=i(()=>g.data??[],[g.data]),w=i(()=>{let e=new Map;for(let t of C)e.set(t.kind,t);return e},[C]);return r(J,{icon:M,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(B,{size:`sm`,type:`button`,onClick:()=>{p(null),o({mode:`pick-kind`})},children:[l(y,{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(Pe,{profiles:S}),h.isLoading&&l(`div`,{className:`flex items-center justify-center py-16`,children:l(E,{className:`h-6 w-6 animate-spin text-primary`})}),!h.isLoading&&S.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.`)}),S.length>0&&l(k,{children:l(F,{columns:Me({kindByName:w,testResult:u,testingId:x.isPending?x.variables?.id??null:null,t:e,onToggle:e=>v.mutate({...e,enabled:!e.enabled,apiKey:`__redacted__`}),onTest:e=>x.mutate(e),onEdit:e=>{let t=w.get(e.kind);t!==void 0&&(p(null),o({mode:`form`,kind:t,profile:e}))},onDelete:e=>b.mutate(e)}),rows:S,rowKey:e=>e.id,minWidthPx:760,bordered:!1,mobileMode:`scroll`,maxBodyHeight:`max-h-[60vh]`})}),n.mode===`pick-kind`&&l(Ae,{kinds:C,onCancel:()=>o({mode:`closed`}),onPick:e=>o({mode:`form`,kind:e,profile:null})}),n.mode===`form`&&l(je,{kind:n.kind,existing:n.profile,saving:v.isPending,error:f,onSave:e=>v.mutate(e),onCancel:()=>o({mode:`closed`})})]})}function Pe({profiles:e}){let{t}=q(),n=m(),i=a({queryKey:ue,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(k,{children:l(`div`,{className:`grid gap-4 p-4 sm:grid-cols-2`,children:me.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 Fe=5e3;function Ie(e){return`${(e/1e9).toFixed(1)} GB`}function Le(){let{t:e}=q(),t=m(),n=a({queryKey:de,refetchInterval:Fe,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(N,{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(N,{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?`—`:Ie(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(J,{icon:G,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(k,{children:l(F,{columns:o,rows:s,rowKey:e=>e.nodeId,minWidthPx:640,bordered:!1,mobileMode:`scroll`,maxBodyHeight:U})})]})}var Re=f(`/addon/ai/test-chat`),ze=f(`/addon/ai/test-chat/chats`),Be=6e5;function Ve(e){let t=e.firstTokenTimeoutMs;if(!(typeof t!=`number`||!Number.isFinite(t)||t<=0))return Math.min(Math.round(t),Be)}function He(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Ue(e){if(!He(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}:{},...typeof e.thumbnailBase64==`string`?{thumbnailBase64:e.thumbnailBase64}:{}}}var We=[`resolving-image`,`connecting`,`first-token-wait`,`streaming`];function Ge(e){let t;try{t=JSON.parse(e)}catch{return null}if(!He(t))return null;switch(t.kind){case`status`:{let e=We.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:Ue(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,...typeof t.conversationId==`string`?{conversationId:t.conversationId}:{}};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*Ke(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=Ge(e);t!==null&&(yield t)}a=r.indexOf(`
|
|
3
|
-
`)}}let e=r.trim();if(e.length>0){let t=Ge(e);t!==null&&(yield t)}}finally{t.releaseLock()}}function qe(e){return e.filter(e=>e.failed!==!0&&e.content.length>0).map(e=>({role:e.role,content:e.content}))}function Je(e){return e.thumbnailBase64===void 0||e.thumbnailBase64.length===0?null:`data:${e.mimeType};base64,${e.thumbnailBase64}`}function Ye(e){return e.messages.map((t,n)=>{let r=t.mediaSent??void 0;return{id:`${e.id}-${String(n)}`,role:t.role,content:t.content,...t.attachment===void 0?{}:{attachmentRef:t.attachment,attachmentKind:t.attachment.kind},...r===void 0?{}:{attachment:r}}})}function Xe(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 Ze(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 Qe=[`pipelineAnalytics`,`listRecentTracks`,`ai-test`],$e=360*60*1e3,et=40,tt=160,$={phase:`connecting`,firstTokenTimeoutMs:0,text:``,mediaSent:null};function nt(){let{t:n}=q(),o=m(),[c,d]=s(``),[f,_]=s(``),[v,y]=s(``),[S,C]=s([]),[w,T]=s(null),[E,D]=s(`none`),[O,ee]=s(`throwaway`),[j,M]=s(null),[N,ne]=s([]),[P,F]=s(null),[I,L]=s(null),R=t(null);u(()=>()=>R.current?.abort(),[]);let z=e(async()=>{let e=await fetch(ze,{credentials:`same-origin`});e.ok&&ne((await e.json()).chats??[])},[]);u(()=>{O===`persistent`&&z()},[O,z]);let V=a({queryKey:ce,queryFn:()=>o.trpcClient.llm.listProfiles.query({})}),H=i(()=>(V.data??[]).filter(e=>e.enabled),[V.data]),U=H.find(e=>e.id===c)??null,G=I!==null,ie=e(async(e,t)=>{let r=new AbortController;R.current=r,F(null);let i=Ve(U??{});L({...$,firstTokenTimeoutMs:i??0});let a=``,o=null,s,l=null,u=null,d;try{let n=await fetch(Re,{method:`POST`,headers:{"content-type":`application/json`},credentials:`same-origin`,signal:r.signal,body:JSON.stringify({profileId:c,messages:e,...f.trim()===``?{}:{system:f.trim()},...t===void 0?{}:{attachment:t},...i===void 0?{}:{firstTokenTimeoutMs:i},...O===`persistent`?{persist:!0,...j===null?{}:{conversationId:j}}:{}})});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 Ke(n.body))switch(e.kind){case`status`:L(t=>({...t??$,phase:e.phase}));break;case`meta`:o=e.mediaSent,s=e.model,L(t=>({...t??$,firstTokenTimeoutMs:e.firstTokenTimeoutMs,mediaSent:e.mediaSent}));break;case`token`:a+=e.text,L(e=>({...e??$,text:a}));break;case`done`:u={outputTokens:e.outputTokens,latencyMs:e.latencyMs},d=e.conversationId;break;case`error`:l=`${e.code}: ${e.message}`;break}}catch(e){r.signal.aborted||F(e instanceof Error?e.message:n(`common.error`,`Error`))}finally{R.current=null,L(null)}d!==void 0&&(M(d),z());let p=r.signal.aborted&&a.length>0;l===null&&a.length===0&&!p||C(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}])},[O,j,U,c,z,f,n]),K=e(()=>{let e=v.trim();if(e===``||c===``||G)return;let t={id:`u-${String(Date.now())}`,role:`user`,content:e,...w===null?{}:{attachmentLabel:w.label,attachmentKind:w.ref.kind}},n=[...S,t];C(n),y(``);let r=w?.ref;T(null),D(`none`),ie(O===`persistent`&&j!==null?[{role:`user`,content:e}]:qe(n),r)},[O,j,v,w,c,ie,G,S]),oe=()=>R.current?.abort(),le=()=>{R.current?.abort(),C([]),T(null),y(``),F(null),L(null),M(null)},ue=async e=>{R.current?.abort();let t=await fetch(`${ze}/${e}`,{credentials:`same-origin`});if(!t.ok)return;let n=await t.json();M(e),C(Ye(n)),L(null),F(null)};return r(J,{icon:te,title:n(`ai.testTitle`,`Test chat`),subtitle:n(O===`persistent`?`ai.testSubtitlePersistent`:`ai.testSubtitle`,O===`persistent`?`Conversations are saved for you and can be reopened. Throwaway mode is still available.`:`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(B,{size:`sm`,variant:`secondary`,type:`button`,disabled:S.length===0&&w===null,onClick:le,children:[l(g,{className:`h-3.5 w-3.5`}),n(`ai.clearChat`,`Clear`)]}),children:[r(k,{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(re,{id:`ai-test-profile`,value:c,onChange:e=>d(e.target.value),options:[{value:``,label:n(`ai.selectProfile`,`Select a profile…`)},...H.map(e=>({value:e.id,label:`${e.name} · ${e.model}${e.supportsVision?` · vision`:``}`}))]}),H.length===0&&!V.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(A,{id:`ai-test-system`,value:f,onChange:e=>_(e.target.value),placeholder:n(`ai.systemPlaceholder`,`Answer in one short sentence.`)})]})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[l(B,{size:`sm`,variant:O===`throwaway`?`primary`:`outline`,type:`button`,onClick:()=>{ee(`throwaway`),M(null)},children:n(`ai.throwawayMode`,`Throwaway`)}),l(B,{size:`sm`,variant:O===`persistent`?`primary`:`outline`,type:`button`,onClick:()=>ee(`persistent`),children:n(`ai.saveConversation`,`Save conversation`)})]}),O===`persistent`&&r(`div`,{className:`space-y-2`,children:[l(`div`,{className:`flex items-center gap-2`,children:r(B,{size:`sm`,variant:`secondary`,type:`button`,onClick:le,children:[l(se,{className:`h-3.5 w-3.5`}),n(`ai.newChat`,`New chat`)]})}),N.length>0&&l(`div`,{className:`max-h-36 divide-y divide-border overflow-y-auto rounded-md border border-border`,children:N.map(e=>l(`button`,{type:`button`,onClick:()=>void ue(e.id),className:`flex w-full px-2.5 py-1.5 text-left text-[11px] hover:bg-surface-hover ${e.id===j?`bg-primary/10`:``}`,children:l(`span`,{className:`min-w-0 flex-1 truncate text-foreground`,children:e.title})},e.id))})]}),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.`)}),U!==null&&!U.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.`)})]}),P!==null&&l(W,{title:n(`ai.chatFailed`,`The test call failed`),message:P}),l(rt,{turns:S,live:I}),r(k,{className:`space-y-2 p-3`,children:[w!==null&&r(`div`,{className:`flex items-center gap-2 rounded-md border border-border bg-surface px-2.5 py-1.5`,children:[w.ref.kind===`snapshot`?l(p,{className:`h-3.5 w-3.5 text-foreground-subtle`}):l(x,{className:`h-3.5 w-3.5 text-foreground-subtle`}),l(`span`,{className:`min-w-0 flex-1 truncate text-[11px] text-foreground`,children:w.label}),l(B,{size:`sm`,variant:`ghost`,type:`button`,onClick:()=>T(null),children:l(b,{className:`h-3.5 w-3.5`})})]}),r(`div`,{className:`flex flex-wrap items-center gap-2`,children:[r(B,{size:`sm`,variant:E===`snapshot`?`primary`:`outline`,type:`button`,onClick:()=>D(E===`snapshot`?`none`:`snapshot`),children:[l(p,{className:`h-3.5 w-3.5`}),n(`ai.attachSnapshot`,`Camera snapshot`)]}),r(B,{size:`sm`,variant:E===`track`?`primary`:`outline`,type:`button`,onClick:()=>D(E===`track`?`none`:`track`),children:[l(x,{className:`h-3.5 w-3.5`}),n(`ai.attachTrack`,`Recent track`)]})]}),E===`snapshot`&&l(ot,{onPick:e=>{T({ref:{kind:`snapshot`,deviceId:e.id},label:n(`ai.snapshotOf`,`Snapshot of {{name}}`,{name:e.name})}),D(`none`)}}),E===`track`&&l(ct,{onPick:(e,t)=>{T({ref:{kind:`track`,trackId:e.trackId,deviceId:e.deviceId},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(A,{value:v,onChange:e=>y(e.target.value),onKeyDown:e=>{e.key===`Enter`&&!e.shiftKey&&(e.preventDefault(),K())},placeholder:n(`ai.messagePlaceholder`,`Ask the model something…`),"aria-label":n(`ai.message`,`Message`)}),G?r(B,{size:`sm`,variant:`secondary`,type:`button`,onClick:oe,children:[l(h,{className:`h-3.5 w-3.5`}),n(`ai.stop`,`Stop`)]}):r(B,{size:`sm`,type:`button`,disabled:v.trim()===``||c===``,onClick:K,children:[l(ae,{className:`h-3.5 w-3.5`}),n(`ai.send`,`Send`)]})]})]})]})}function rt({turns:e,live:t}){let{t:n}=q();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(k,{children:r(`div`,{className:`max-h-[50vh] space-y-2 overflow-y-auto p-3`,children:[e.map(e=>l(it,{turn:e},e.id)),t!==null&&r(`div`,{className:`space-y-1`,children:[t.mediaSent!==null&&l(at,{attachment:t.mediaSent}),t.text.length>0&&l(it,{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(E,{className:`h-3.5 w-3.5 animate-spin`}),Ze(t.phase,t.firstTokenTimeoutMs)]})]})]})})}function it({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.attachment!==void 0&&l(at,{attachment:e.attachment}),e.attachmentLabel!==void 0&&r(`p`,{className:`mt-1 flex items-center gap-1 text-[10px] text-foreground-subtle`,children:[e.attachmentKind===`track`?l(x,{className:`h-3 w-3`}):l(p,{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(p,{className:`h-3 w-3`}):l(x,{className:`h-3 w-3`}),Xe(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 at({attachment:e}){let t=Je(e);return t===null?null:l(`img`,{src:t,alt:`sent to the model`,className:`mt-1 max-h-32 rounded-md border border-border object-contain`})}function ot({onPick:e}){let{t}=q(),n=z({isCamera:!0,projection:`slim`}),r=(n.data??[]).filter(e=>!e.disabled);return n.isLoading?l(E,{className:`h-4 w-4 animate-spin text-foreground-subtle`}):r.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:r.map(t=>l(st,{device:t,onPick:e},t.id))})}function st({device:e,onPick:t}){let{src:n}=d(e.id,{width:tt});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(N,{variant:`warning`,children:`off`}),l(`span`,{className:`truncate text-[10px] text-foreground`,children:e.name})]})]})}function ct({onPick:e}){let{t}=q(),n=m(),o=z({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:[...Qe,s.length],enabled:s.length>0,queryFn:()=>n.trpcClient.pipelineAnalytics.listRecentTracks.query({deviceIds:[...s],since:Date.now()-$e,limit:et,projection:`slim`})});if(o.isLoading||u.isLoading)return l(E,{className:`h-4 w-4 animate-spin text-foreground-subtle`});let d=u.data?.tracks??[];return d.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:d.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(x,{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 lt=1440*60*1e3,ut=[1,7,30,90];function dt(){let{t:e}=q(),t=m(),[n,o]=s(7),c=i(()=>{let e=new Date;return e.setHours(0,0,0,0),e.getTime()-(n-1)*lt},[n]),u=a({queryKey:ce,queryFn:()=>t.trpcClient.llm.listProfiles.query({})}),d=a({queryKey:[...pe,n],queryFn:()=>t.trpcClient.llm.getUsage.query({since:c})}),f=i(()=>{let e=new Map;for(let t of u.data??[])e.set(t.id,t.name);return e},[u.data]),p=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:f.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))}],[f,e]),h=d.data??[];return r(J,{icon:w,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(re,{"aria-label":e(`ai.window`,`Window`),value:String(n),options:ut.map(t=>({value:String(t),label:e(`ai.lastDays`,`Last {{days}} days`,{days:t})})),onChange:e=>o(Number(e.target.value))})}),children:[d.isError&&l(W,{title:e(`ai.usageFailed`,`Failed to read usage`),message:d.error instanceof Error?d.error.message:e(`common.error`,`Error`),onRetry:()=>void d.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(k,{children:l(F,{columns:p,rows:h,rowKey:e=>`${e.day}|${e.consumer}|${e.profileId}`,minWidthPx:720,bordered:!1,mobileMode:`scroll`,maxBodyHeight:U})})]})}function ft(){let{t:e}=q();return l(`div`,{className:`flex flex-col p-4`,children:l(oe,{tabs:[{id:`profiles`,label:e(`ai.tabProfiles`,`Profiles`),icon:ie,content:l(Ne,{})},{id:`runtimes`,label:e(`ai.tabRuntimes`,`Runtimes`),icon:G,content:l(Le,{})},{id:`usage`,label:e(`ai.tabUsage`,`Usage`),icon:w,content:l(dt,{})},{id:`test`,label:e(`ai.tabTest`,`Test`),icon:te,content:l(nt,{})}]})})}export{ft as AiProfilesPage,ft as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Q as e,S as t,W as n,b as r,o as i,q as a,x as o}from"./_virtual_mf___mfe_internal__admin_ui_host__loadShare___mf_0_tanstack_mf_1_react_mf_2_query__loadShare__.js-DhP-Lgiq.js";import{st as s}from"./player-overlays-CjslyEYg.js";import{Ac as c,Bn as l,Cl as u,Cr as d,Dc as f,Dr as p,Er as m,Ll as h,Nr as g,Or as _,Pl as v,Sl as y,T as b,Tl as x,Tr as S,br as C,cl as w,hn as T,wr as E,xr as D,yl as ee}from"./src-yMwlDObw.js";import{St as O,Tt as k,U as A}from"./src-DPG5IJP-.js";import{a as j}from"./index-Bxt1Fjnf.js";import{t as M}from"./AdminPage-CiKtOLQm.js";import{t as N}from"./AdminTabs-BGbLei2R.js";import{t as P}from"./BrokerForm-CRihFbyu.js";import{t as F}from"./useBodyScrollLock-BDocajQE.js";import{t as I}from"./AddonCollectionPage-CX0Adg6B.js";e();var L={"home-assistant":`Home Assistant`,mqtt:`MQTT`};function R(e){return L[e]??e}function z(e){return Array.isArray(e)?e.filter(e=>typeof e==`object`&&!!e&&typeof e.addonId==`string`&&Array.isArray(e.kinds)):[]}var B={connected:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`,connecting:`bg-amber-500/15 text-amber-700 dark:text-amber-300`,disconnected:`bg-foreground-subtle/15 text-foreground-subtle`,"auth-failed":`bg-danger/15 text-danger`,unreachable:`bg-danger/15 text-danger`,error:`bg-danger/15 text-danger`};function V({status:e}){return o(`span`,{className:`text-[10px] rounded-full px-2 py-0.5 font-medium ${B[e]}`,children:e})}function H(e){return Array.isArray(e)?e.filter(e=>typeof e==`object`&&!!e&&typeof e.id==`string`):[]}function U({title:e,subtitle:n,onClose:r,children:i}){return F(),o(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-background/80 backdrop-blur-sm`,onClick:r,children:t(`div`,{className:`w-full max-w-md rounded-xl border border-border bg-surface shadow-2xl`,onClick:e=>e.stopPropagation(),children:[t(`div`,{className:`flex items-start justify-between border-b border-border px-4 py-3`,children:[t(`div`,{className:`space-y-0.5`,children:[o(`h2`,{className:`text-sm font-semibold text-foreground`,children:e}),n&&o(`p`,{className:`text-xs text-foreground-subtle`,children:n})]}),o(`button`,{onClick:r,className:`text-foreground-subtle hover:text-foreground`,children:o(f,{className:`h-4 w-4`})})]}),o(`div`,{className:`p-4 max-h-[70vh] overflow-y-auto overscroll-contain`,children:i})]})})}function W({kinds:e,onClose:n,onDone:s}){let c=i(),l=e=>`${e.addonId??``}::${e.kind}`,[u,d]=a(e[0]?l(e[0]):``),[f,p]=a(``),[m,h]=a(!1),[g,_]=a(``),v=e.find(e=>l(e)===u)??e[0],y=v?.kind??``,b=v?.addonId,x=C({onSuccess:()=>{c.invalidateQueries({queryKey:[[`broker`,`list`]]}),s()}}),S=e=>{if(!y||f.trim().length===0)return;let t=m?g.trim():``;m&&t===``||x.mutate({kind:y,name:f.trim(),settings:e,...t===``?{}:{id:t},...b===void 0?{}:{addonId:b}})};return o(U,{title:`Add broker`,subtitle:`Register a message broker for exporters and automations.`,onClose:x.isPending?()=>{}:n,children:t(`div`,{className:`space-y-3`,children:[t(`div`,{className:`space-y-1`,children:[o(`label`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle`,children:`Kind`}),o(`select`,{value:u,onChange:e=>d(e.target.value),className:`w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary`,children:e.map(e=>o(`option`,{value:l(e),children:e.label},l(e)))})]}),t(`div`,{className:`space-y-1`,children:[o(`label`,{className:`text-[10px] uppercase tracking-wide text-foreground-subtle`,children:`Name`}),o(`input`,{type:`text`,value:f,onChange:e=>p(e.target.value),placeholder:`My Home Assistant`,className:`w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary`})]}),t(`div`,{className:`space-y-1 rounded border border-border px-3 py-2`,children:[t(`label`,{className:`flex items-center gap-2 text-[11px] text-foreground`,children:[o(`input`,{type:`checkbox`,checked:m,onChange:e=>h(e.target.checked)}),`Restore a broker that was removed, under its original id`]}),m&&t(r,{children:[o(`input`,{type:`text`,value:g,onChange:e=>_(e.target.value),placeholder:`ha_004`,className:`w-full rounded border border-border bg-background px-2 py-1.5 text-xs text-foreground focus:outline-none focus:ring-1 focus:ring-primary`}),o(`p`,{className:`text-[10px] text-foreground-subtle`,children:`Devices remember the broker id they were discovered under, so restoring the original id reconnects them instead of needing re-discovery. An id that is still in use is refused.`})]})]}),x.isError&&o(`div`,{className:`rounded border border-danger/30 bg-danger/5 text-danger px-3 py-2 text-[11px]`,children:x.error instanceof Error?x.error.message:String(x.error)}),y&&o(P,{kind:y,...b===void 0?{}:{addonId:b},onSubmit:S,onCancel:n,submitLabel:x.isPending?`Adding…`:`Add broker`,disabled:x.isPending}),f.trim().length===0&&o(`p`,{className:`text-[10px] text-foreground-subtle`,children:`Enter a name before saving.`}),m&&g.trim().length===0&&o(`p`,{className:`text-[10px] text-foreground-subtle`,children:`Enter the original id, or clear the checkbox to create a new broker.`})]})})}function G({broker:e,onClose:r,onDone:a}){let s=i(),c=D({id:e.id,addonId:e.addonId}),l=p({onSuccess:()=>{s.invalidateQueries({queryKey:[[`broker`,`list`]]}),s.invalidateQueries({queryKey:[[`broker`,`getSettings`],{input:{id:e.id,addonId:e.addonId}}]}),a()}}),u=n(()=>{let e=c.data;return e&&typeof e==`object`?{...e}:{}},[c.data]);return o(U,{title:`Edit ${e.name}`,subtitle:`${R(e.kind)} · ${e.id}`,onClose:l.isPending?()=>{}:r,children:c.isLoading?t(`div`,{className:`flex items-center gap-2 text-xs text-foreground-subtle`,children:[o(h,{className:`h-3.5 w-3.5 animate-spin`}),` Loading settings…`]}):c.isError?t(`div`,{className:`space-y-3`,children:[t(`div`,{className:`rounded border border-danger/30 bg-danger/5 text-danger px-3 py-2 text-[11px]`,children:[`Failed to load settings:`,` `,c.error instanceof Error?c.error.message:`Unknown error`]}),o(`div`,{className:`flex justify-end`,children:o(`button`,{type:`button`,onClick:r,className:`rounded px-3 py-1.5 text-xs text-foreground-subtle border border-border hover:text-foreground`,children:`Close`})})]}):t(`div`,{className:`space-y-3`,children:[l.isError&&o(`div`,{className:`rounded border border-danger/30 bg-danger/5 text-danger px-3 py-2 text-[11px]`,children:l.error instanceof Error?l.error.message:String(l.error)}),o(P,{kind:e.kind,addonId:e.addonId,initialValues:u,onSubmit:t=>{l.mutate({id:e.id,settings:t,addonId:e.addonId})},onCancel:r,submitLabel:l.isPending?`Saving…`:`Save`,disabled:l.isPending})]})})}function K({broker:e,onEdit:n}){let r=i(),l=T(),[u,d]=a(null),f=_({onSuccess:e=>d(e.ok?{ok:!0}:{ok:!1,error:e.error}),onError:e=>d({ok:!1,error:e instanceof Error?e.message:String(e)})}),p=m({onSuccess:()=>{r.invalidateQueries({queryKey:[[`broker`,`list`]]})}}),g=async()=>{await l({title:`Delete broker`,message:`Delete broker "${e.name}"? Integrations that depend on it will stop working.`,confirmLabel:`Delete`,variant:`danger`})&&p.mutate({id:e.id,addonId:e.addonId})};return t(`tr`,{className:`border-b border-border last:border-0`,children:[o(`td`,{className:`px-3 py-2 text-xs text-foreground font-medium`,children:e.name}),o(`td`,{className:`px-3 py-2 text-xs text-foreground-subtle`,children:R(e.kind)}),t(`td`,{className:`px-3 py-2`,children:[o(V,{status:e.status}),u&&o(`span`,{className:`ml-2 text-[10px] ${u.ok?`text-success`:`text-danger`}`,children:u.ok?`OK`:u.error??`failed`})]}),o(`td`,{className:`px-3 py-2`,children:t(`div`,{className:`flex items-center justify-end gap-1.5`,children:[t(`button`,{type:`button`,onClick:()=>f.mutate({id:e.id,addonId:e.addonId}),disabled:f.isPending,title:`Test connection`,className:`inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[11px] text-foreground hover:bg-primary/10 disabled:opacity-50`,children:[f.isPending?o(h,{className:`h-3 w-3 animate-spin`}):o(c,{className:`h-3 w-3`}),`Test`]}),t(`button`,{type:`button`,onClick:()=>n(e),title:`Edit`,className:`inline-flex items-center gap-1 rounded border border-border px-2 py-1 text-[11px] text-foreground hover:bg-primary/10`,children:[o(x,{className:`h-3 w-3`}),` Edit`]}),t(`button`,{type:`button`,onClick:()=>{g()},disabled:p.isPending,title:`Delete`,className:`inline-flex items-center gap-1 rounded border border-danger/40 px-2 py-1 text-[11px] text-danger hover:bg-danger/10 disabled:opacity-50`,children:[p.isPending?o(h,{className:`h-3 w-3 animate-spin`}):o(s,{className:`h-3 w-3`}),`Delete`]})]})})]})}function q(){let e=E({}),r=S(),i=n(()=>H(e.data),[e.data]),[s,c]=a(!1),[l,d]=a(null),f=n(()=>{let e=new Map;for(let t of z(r.data))for(let n of t.kinds)e.set(`${t.addonId}::${n.kind}`,{addonId:t.addonId,kind:n.kind,label:n.label});for(let t of i)[...e.values()].some(e=>e.kind===t.kind)||e.set(`::${t.kind}`,{kind:t.kind,label:R(t.kind)});return[...e.values()]},[i,r.data]);return t(`div`,{className:`space-y-3`,children:[o(`div`,{className:`flex items-center justify-end`,children:t(`button`,{type:`button`,onClick:()=>c(!0),disabled:f.length===0,title:f.length===0?`No broker providers available`:void 0,className:`inline-flex items-center gap-1.5 rounded-lg bg-primary px-3 py-1.5 text-xs font-medium text-primary-foreground hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed`,children:[o(u,{className:`h-3.5 w-3.5`}),` Add broker`]})}),o(`div`,{className:`rounded-lg border border-border bg-surface overflow-x-auto`,children:t(`table`,{className:`w-full min-w-[36rem] border-collapse`,children:[o(`thead`,{children:t(`tr`,{className:`border-b border-border bg-background/50`,children:[o(`th`,{className:`px-3 py-2 text-left text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:`Name`}),o(`th`,{className:`px-3 py-2 text-left text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:`Kind`}),o(`th`,{className:`px-3 py-2 text-left text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:`Status`}),o(`th`,{className:`px-3 py-2 text-right text-[10px] font-semibold uppercase tracking-wider text-foreground-subtle`,children:`Actions`})]})}),t(`tbody`,{children:[e.isLoading&&o(`tr`,{children:t(`td`,{colSpan:4,className:`px-3 py-6 text-center text-xs text-foreground-subtle`,children:[o(h,{className:`inline h-4 w-4 animate-spin`}),` Loading brokers…`]})}),e.isError&&o(`tr`,{children:t(`td`,{colSpan:4,className:`px-3 py-4 text-center text-xs text-danger`,children:[`Failed to load brokers:`,` `,e.error instanceof Error?e.error.message:`Unknown error`]})}),!e.isLoading&&!e.isError&&i.length===0&&o(`tr`,{children:o(`td`,{colSpan:4,className:`px-3 py-6 text-center text-xs text-foreground-subtle`,children:`No brokers registered yet. Add one to publish device events for downstream automations.`})}),i.map(e=>o(K,{broker:e,onEdit:d},e.id))]})]})}),s&&o(W,{kinds:f,onClose:()=>c(!1),onDone:()=>c(!1)}),l&&o(G,{broker:l,onClose:()=>d(null),onDone:()=>d(null)})]})}var J=[{kind:`device-export`,tabId:`device-export`,title:`Device export`,subtitle:`Outbound exporters that publish CamStack devices to other ecosystems (HomeAssistant, HomeKit, Alexa, …).`,icon:w,emptyTitle:`No device-export providers installed`,emptyDescription:`Install an export addon (e.g. @camstack/addon-export-ha-mqtt) to surface your CamStack devices in HomeAssistant, HomeKit, …`,addLabel:`Add export`},{kind:`email`,tabId:`email`,title:`Email providers`,subtitle:`Outbound email relays used for magic-link login, notifications, and alerts (SMTP today, future SendGrid, …).`,icon:v,emptyTitle:`No email providers installed`,emptyDescription:`Install an email-provider addon (e.g. @camstack/addon-smtp) so the hub can deliver magic-link logins and notifications.`,addLabel:`Add email provider`},{kind:`broker`,tabId:`broker`,title:`Brokers`,subtitle:`Message brokers consumed by exporters and downstream automations (MQTT today, future Kafka, …).`,icon:ee,emptyTitle:`No brokers installed`,emptyDescription:`Install a broker addon (e.g. @camstack/addon-mqtt-broker) to publish device events for downstream automations.`,addLabel:`Add broker`}];function Y(e){if(typeof e==`string`)return e;if(e&&typeof e==`object`){let t=e.name;if(typeof t==`string`)return t}return null}function X(e){let t=e,n=t?.manifest;if(!n?.id)return null;let r=[];for(let e of n.capabilities??[]){let t=Y(e);t!==null&&r.push(t)}let i=n.packageDisplayName??n.name??n.id,a=t?.process?.state??null;return{addonId:n.id,displayName:i,isActive:a===`running`,packageName:n.packageName??`@camstack/addon-${n.id}`,capNames:r,processState:a}}function Z(e,t){let n=new Set(t);return e.filter(e=>e.capNames.some(e=>n.has(e)))}function Q(e){for(let[t,n]of Object.entries(A))if(n===e)return t;return null}function te(e){return e===`running`?{label:`Running`,className:`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`}:e===`crashed`||e===`failed`?{label:e===`failed`?`Failed`:`Crashed`,className:`bg-danger/15 text-danger`}:e===`stopped`||e===`disabled`?{label:`Stopped`,className:`bg-foreground-subtle/15 text-foreground-subtle`}:{label:e??`Unknown`,className:`bg-foreground-subtle/15 text-foreground-subtle`}}function $({label:e,className:t}){return o(`span`,{className:`text-[10px] rounded-full px-2 py-0.5 font-medium ${t}`,children:e})}function ne({addonId:e}){let{data:t,isLoading:n}=d({addonId:e},{refetchInterval:1e4,retry:!1});if(n||!t)return null;let r=k.safeParse(t);if(!r.success)return null;let i=r.data;return o($,{label:`${i.brokerCount} broker${i.brokerCount===1?``:`s`}${i.connectedCount>0?` • ${i.connectedCount} connected`:``}`,className:`bg-primary/10 text-primary`})}function re({addonId:e}){let{data:t,isLoading:n}=g({addonId:e},{refetchInterval:1e4,retry:!1});if(n||!t)return null;let r=O.safeParse(t);if(!r.success)return null;let i=r.data,a=i.linkState===`linked`?`bg-emerald-500/15 text-emerald-700 dark:text-emerald-300`:i.linkState===`error`?`bg-danger/15 text-danger`:`bg-foreground-subtle/15 text-foreground-subtle`;return o($,{label:`${i.linkState} • ${i.exposedDeviceCount} exposed`,className:a})}function ie({kind:e,addonId:t}){return e===`broker`?o(ne,{addonId:t}):e===`device-export`?o(re,{addonId:t}):null}function ae({descriptor:e,rows:n,isLoading:i}){let a=Q(e.kind),s=e.kind===`device-export`,c=j();return o(I,{title:e.title,subtitle:e.subtitle,pageIcon:e.icon,itemIcon:e.icon,capability:a??e.kind,installButtonLabel:e.addLabel,items:n,isLoading:i,emptyTitle:e.emptyTitle,emptyDescription:e.emptyDescription,renderStatusBadges:n=>{let i=te(n.processState);return t(r,{children:[o($,{label:i.label,className:i.className}),o(ie,{kind:e.kind,addonId:n.addonId})]})},renderExpandedPanel:s?e=>o(b,{addonId:e.addonId,onOpenDevice:e=>c(`/devices/${e}`)}):void 0,showChrome:!0})}function oe(){let e=l(void 0,{refetchInterval:1e4}),t=(e.data??[]).map(X).filter(e=>e!==null);return o(M,{icon:y,title:`External systems`,subtitle:`External systems this hub talks to — device exporters, email relays, and message brokers. Settings, Logs and Events are docked under every provider.`,children:o(N,{tabs:J.map(n=>{let r=Object.entries(A).filter(([,e])=>e===n.kind).map(([e])=>e),i=n.kind===`broker`?o(q,{}):o(ae,{descriptor:n,rows:Z(t,r),isLoading:e.isLoading});return{id:n.tabId,label:n.title,icon:n.icon,content:i}})})})}export{oe as IntegrationsPage};
|