rhombus-node-mcp 0.1.43 → 0.1.45
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/api/badge-correlation.js +33 -0
- package/dist/api/badge-timeline-tool-api.js +56 -0
- package/dist/api/onguard-tool-api.js +44 -0
- package/dist/tools-console/badge-timeline-tool.js +50 -0
- package/dist/tools-console/onguard-tool.js +55 -0
- package/dist/types/badge-timeline-tool-types.js +75 -0
- package/dist/types/onguard-tool-types.js +70 -0
- package/dist/types/zod-schemas.js +27 -0
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Keystone correlation helper for the OnGuard feature set.
|
|
3
|
+
*
|
|
4
|
+
* Given a badge-event-like entry (a camera `deviceUuid` + a `timestampMs`), produce the media hints
|
|
5
|
+
* the agent needs to *show* the moment: a still (camera-tool `image`) and a short clip window
|
|
6
|
+
* (clips-tool `createClip`). Pure and reusable — the follow-the-badge timeline, anomaly review, and
|
|
7
|
+
* lost-badge tracking all turn badge events into "here's the picture/video" the same way.
|
|
8
|
+
*
|
|
9
|
+
* Kept deliberately small and side-effect-free. Richer correlation (co-located face events,
|
|
10
|
+
* people-count in the window) layers on top of this when those features land.
|
|
11
|
+
*/
|
|
12
|
+
export const DEFAULT_CLIP_PADDING_SECONDS = 15;
|
|
13
|
+
/**
|
|
14
|
+
* Build still + clip hints for a single badge event. Returns empty hints (no clip/still) when the
|
|
15
|
+
* event lacks a camera or timestamp, so callers can render those events without media gracefully.
|
|
16
|
+
*/
|
|
17
|
+
export function buildMediaHints(event, clipPaddingSeconds = DEFAULT_CLIP_PADDING_SECONDS) {
|
|
18
|
+
if (!event.deviceUuid || event.timestampMs == null) {
|
|
19
|
+
return {};
|
|
20
|
+
}
|
|
21
|
+
const padMs = Math.max(0, clipPaddingSeconds) * 1000;
|
|
22
|
+
return {
|
|
23
|
+
clipHint: {
|
|
24
|
+
deviceUuid: event.deviceUuid,
|
|
25
|
+
startTimeMs: event.timestampMs - padMs,
|
|
26
|
+
endTimeMs: event.timestampMs + padMs,
|
|
27
|
+
},
|
|
28
|
+
stillHint: {
|
|
29
|
+
deviceUuid: event.deviceUuid,
|
|
30
|
+
timestampMs: event.timestampMs,
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { buildMediaHints } from "./badge-correlation.js";
|
|
2
|
+
import { searchOnGuardEvents } from "./onguard-tool-api.js";
|
|
3
|
+
/**
|
|
4
|
+
* Reconstructs a single cardholder's movements as a chronological timeline of OnGuard badge taps,
|
|
5
|
+
* each with the still/clip hints needed to show what happened. Pure orchestration over
|
|
6
|
+
* searchOnGuardEvents + the shared correlation helper.
|
|
7
|
+
*/
|
|
8
|
+
export async function getBadgeTimeline(args, timeZone, requestModifiers, sessionId) {
|
|
9
|
+
const { events } = await searchOnGuardEvents({
|
|
10
|
+
cardholderQuery: args.cardholderQuery,
|
|
11
|
+
locationUuids: args.locationUuids,
|
|
12
|
+
afterMs: args.afterMs,
|
|
13
|
+
beforeMs: args.beforeMs,
|
|
14
|
+
limit: args.limit ?? 200,
|
|
15
|
+
}, timeZone, requestModifiers, sessionId);
|
|
16
|
+
// searchOnGuardEvents returns newest-first; a timeline reads chronologically.
|
|
17
|
+
const ordered = events
|
|
18
|
+
.filter((e) => e.timestampMs != null)
|
|
19
|
+
.sort((a, b) => (a.timestampMs ?? 0) - (b.timestampMs ?? 0));
|
|
20
|
+
const stops = ordered.map((e, i) => {
|
|
21
|
+
const next = ordered[i + 1];
|
|
22
|
+
const gapToNextSeconds = next?.timestampMs != null && e.timestampMs != null
|
|
23
|
+
? Math.round((next.timestampMs - e.timestampMs) / 1000)
|
|
24
|
+
: undefined;
|
|
25
|
+
const { clipHint, stillHint } = buildMediaHints({ deviceUuid: e.deviceUuid, timestampMs: e.timestampMs }, args.clipPaddingSeconds);
|
|
26
|
+
return {
|
|
27
|
+
timestampMs: e.timestampMs,
|
|
28
|
+
datetime: e.datetime,
|
|
29
|
+
deviceUuid: e.deviceUuid,
|
|
30
|
+
area: e.areaEntering ?? e.areaExiting,
|
|
31
|
+
label: e.label,
|
|
32
|
+
isAnomaly: e.isAnomaly,
|
|
33
|
+
clipHint,
|
|
34
|
+
stillHint,
|
|
35
|
+
gapToNextSeconds,
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
// The sequence of areas traversed, collapsing consecutive repeats.
|
|
39
|
+
const path = [];
|
|
40
|
+
for (const stop of stops) {
|
|
41
|
+
if (stop.area && stop.area !== path[path.length - 1]) {
|
|
42
|
+
path.push(stop.area);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
// cardholderQuery is full-text, so it can match more than one person — surface that so the agent
|
|
46
|
+
// can disambiguate rather than silently merge two people's movements.
|
|
47
|
+
const distinctCardholders = [
|
|
48
|
+
...new Set(ordered.map((e) => e.cardholderName).filter((n) => !!n)),
|
|
49
|
+
];
|
|
50
|
+
return {
|
|
51
|
+
cardholderName: distinctCardholders[0],
|
|
52
|
+
ambiguousCardholders: distinctCardholders.length > 1 ? distinctCardholders : undefined,
|
|
53
|
+
stops,
|
|
54
|
+
path,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { postApi } from "../network/network.js";
|
|
2
|
+
import { formatTimestamp } from "../util.js";
|
|
3
|
+
/**
|
|
4
|
+
* Calls the webservice OnGuard event search (POST /eventSearchV2/searchOnGuardEvents) and maps the
|
|
5
|
+
* raw seekpoints to an agent-friendly shape. Typed against the generated public OpenAPI schema.
|
|
6
|
+
*/
|
|
7
|
+
export async function searchOnGuardEvents(args, timeZone, requestModifiers, sessionId) {
|
|
8
|
+
const body = {
|
|
9
|
+
deviceUuids: args.deviceUuids,
|
|
10
|
+
locationUuids: args.locationUuids,
|
|
11
|
+
afterMs: args.afterMs,
|
|
12
|
+
beforeMs: args.beforeMs,
|
|
13
|
+
cardholderQuery: args.cardholderQuery,
|
|
14
|
+
badgeStatus: args.badgeStatus,
|
|
15
|
+
badgeType: args.badgeType,
|
|
16
|
+
area: args.area,
|
|
17
|
+
anomalyOnly: args.anomalyOnly,
|
|
18
|
+
entryMade: args.entryMade,
|
|
19
|
+
limit: args.limit ?? 200,
|
|
20
|
+
};
|
|
21
|
+
const res = await postApi({
|
|
22
|
+
route: "/eventSearchV2/searchOnGuardEvents",
|
|
23
|
+
body,
|
|
24
|
+
modifiers: requestModifiers,
|
|
25
|
+
sessionId,
|
|
26
|
+
});
|
|
27
|
+
if (res.error) {
|
|
28
|
+
throw new Error(res.status ?? res.errorMsg ?? "OnGuard event search failed");
|
|
29
|
+
}
|
|
30
|
+
const events = (res.events ?? []).map((e) => ({
|
|
31
|
+
timestampMs: e.timestampMs ?? undefined,
|
|
32
|
+
datetime: e.timestampMs != null ? formatTimestamp(e.timestampMs, timeZone) : undefined,
|
|
33
|
+
deviceUuid: e.deviceUuid ?? undefined,
|
|
34
|
+
label: e.customDisplayName ?? undefined,
|
|
35
|
+
cardholderName: e.customDescription ?? undefined,
|
|
36
|
+
badgeStatus: e.badgeStatus ?? undefined,
|
|
37
|
+
badgeType: e.badgeType ?? undefined,
|
|
38
|
+
areaEntering: e.areaEntering ?? undefined,
|
|
39
|
+
areaExiting: e.areaExiting ?? undefined,
|
|
40
|
+
entryMade: e.entryMade ?? undefined,
|
|
41
|
+
isAnomaly: e.alert ?? undefined,
|
|
42
|
+
}));
|
|
43
|
+
return { events };
|
|
44
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getBadgeTimeline } from "../api/badge-timeline-tool-api.js";
|
|
2
|
+
import { OUTPUT_SCHEMA, TOOL_ARGS } from "../types/badge-timeline-tool-types.js";
|
|
3
|
+
import { createToolStructuredContent, extractFromToolExtra } from "../util.js";
|
|
4
|
+
const TOOL_NAME = "badge-timeline-tool";
|
|
5
|
+
const TOOL_DESCRIPTION = `
|
|
6
|
+
Reconstructs one person's movements through a building from their Honeywell OnGuard (Lenel) badge taps.
|
|
7
|
+
Use this for incident reconstruction / "follow the badge" requests, e.g. "reconstruct Eve's movements
|
|
8
|
+
yesterday" or "where did this cardholder go".
|
|
9
|
+
|
|
10
|
+
Returns the cardholder's badge taps in CHRONOLOGICAL order (oldest first), each with:
|
|
11
|
+
- datetime / timestampMs and the area entered
|
|
12
|
+
- deviceUuid: the camera at that door
|
|
13
|
+
- clipHint (camera + start/end window) and stillHint (camera + timestamp)
|
|
14
|
+
- gapToNextSeconds: time until the next tap (a large gap = unobserved movement between doors)
|
|
15
|
+
plus a "path" array summarizing the areas traversed in order.
|
|
16
|
+
|
|
17
|
+
Resolve relative times like "yesterday" to ISO 8601 first (use the timestamp tool), then pass
|
|
18
|
+
startTime/endTime. cardholderQuery is a full-text name match; if "ambiguousCardholders" is returned the
|
|
19
|
+
query matched more than one person — ask the user which one before trusting the timeline.
|
|
20
|
+
|
|
21
|
+
IMPORTANT — to show the movement visually: for each stop (or the key transitions), call the camera-tool
|
|
22
|
+
(requestType "image", cameraUuid = stop.deviceUuid, timestamp = stop.timestampMs) for a still you can see,
|
|
23
|
+
and/or the clips-tool (requestType "createClip", using stop.clipHint) for video. Issue those per-stop
|
|
24
|
+
media calls in PARALLEL, then present the timeline as a chronological narrative.
|
|
25
|
+
`;
|
|
26
|
+
const TOOL_HANDLER = async (args, _extra) => {
|
|
27
|
+
const { requestModifiers, sessionId } = extractFromToolExtra(_extra);
|
|
28
|
+
try {
|
|
29
|
+
const result = await getBadgeTimeline({
|
|
30
|
+
cardholderQuery: args.cardholderQuery,
|
|
31
|
+
locationUuids: args.locationUuids ?? undefined,
|
|
32
|
+
afterMs: args.startTime ? new Date(args.startTime).getTime() : undefined,
|
|
33
|
+
beforeMs: args.endTime ? new Date(args.endTime).getTime() : undefined,
|
|
34
|
+
clipPaddingSeconds: args.clipPaddingSeconds ?? undefined,
|
|
35
|
+
limit: args.limit ?? undefined,
|
|
36
|
+
}, args.timeZone ?? "UTC", requestModifiers, sessionId);
|
|
37
|
+
return createToolStructuredContent(result);
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
41
|
+
return createToolStructuredContent({ error: message });
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export function createTool(server) {
|
|
45
|
+
server.registerTool(TOOL_NAME, {
|
|
46
|
+
description: TOOL_DESCRIPTION,
|
|
47
|
+
inputSchema: TOOL_ARGS,
|
|
48
|
+
outputSchema: OUTPUT_SCHEMA.shape,
|
|
49
|
+
}, TOOL_HANDLER);
|
|
50
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { searchOnGuardEvents } from "../api/onguard-tool-api.js";
|
|
2
|
+
import { OUTPUT_SCHEMA, TOOL_ARGS } from "../types/onguard-tool-types.js";
|
|
3
|
+
import { createToolStructuredContent, extractFromToolExtra } from "../util.js";
|
|
4
|
+
const TOOL_NAME = "onguard-events-tool";
|
|
5
|
+
const TOOL_DESCRIPTION = `
|
|
6
|
+
Searches Honeywell OnGuard (Lenel) badge / access-control events for the organization. Use this to answer
|
|
7
|
+
"who entered WHERE and WHEN" questions, e.g. "who entered the back office yesterday".
|
|
8
|
+
|
|
9
|
+
Each returned event includes:
|
|
10
|
+
- cardholderName: the person's name
|
|
11
|
+
- deviceUuid: the camera that saw the event
|
|
12
|
+
- timestampMs / datetime: when it happened
|
|
13
|
+
- label: e.g. "OnGuard: Badge Authorized" (a grant) or an anomaly label
|
|
14
|
+
- badgeStatus, badgeType, areaEntering, areaExiting, entryMade, isAnomaly
|
|
15
|
+
|
|
16
|
+
Filters (all optional): area, locationUuids, deviceUuids, cardholderQuery, badgeStatus, badgeType,
|
|
17
|
+
anomalyOnly, entryMade, startTime, endTime, limit. Resolve relative times like "yesterday" to ISO 8601
|
|
18
|
+
first (use the timestamp tool), then pass startTime/endTime.
|
|
19
|
+
|
|
20
|
+
IMPORTANT — to show pictures and video of each person so the user can visually identify them: after this
|
|
21
|
+
returns, for each event (or the most relevant ones) call the camera-tool (requestType "image",
|
|
22
|
+
cameraUuid = the event's deviceUuid, timestamp = the event's time) to get a still you can see, and/or the
|
|
23
|
+
clips-tool (requestType "createClip") with a short window around the timestamp for video. Issue those
|
|
24
|
+
per-event media calls in PARALLEL.
|
|
25
|
+
`;
|
|
26
|
+
const TOOL_HANDLER = async (args, _extra) => {
|
|
27
|
+
const { requestModifiers, sessionId } = extractFromToolExtra(_extra);
|
|
28
|
+
try {
|
|
29
|
+
const result = await searchOnGuardEvents({
|
|
30
|
+
area: args.area ?? undefined,
|
|
31
|
+
locationUuids: args.locationUuids ?? undefined,
|
|
32
|
+
deviceUuids: args.deviceUuids ?? undefined,
|
|
33
|
+
cardholderQuery: args.cardholderQuery ?? undefined,
|
|
34
|
+
badgeStatus: args.badgeStatus ?? undefined,
|
|
35
|
+
badgeType: args.badgeType ?? undefined,
|
|
36
|
+
anomalyOnly: args.anomalyOnly ?? undefined,
|
|
37
|
+
entryMade: args.entryMade ?? undefined,
|
|
38
|
+
afterMs: args.startTime ? new Date(args.startTime).getTime() : undefined,
|
|
39
|
+
beforeMs: args.endTime ? new Date(args.endTime).getTime() : undefined,
|
|
40
|
+
limit: args.limit ?? undefined,
|
|
41
|
+
}, args.timeZone ?? "UTC", requestModifiers, sessionId);
|
|
42
|
+
return createToolStructuredContent(result);
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
46
|
+
return createToolStructuredContent({ error: message });
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export function createTool(server) {
|
|
50
|
+
server.registerTool(TOOL_NAME, {
|
|
51
|
+
description: TOOL_DESCRIPTION,
|
|
52
|
+
inputSchema: TOOL_ARGS,
|
|
53
|
+
outputSchema: OUTPUT_SCHEMA.shape,
|
|
54
|
+
}, TOOL_HANDLER);
|
|
55
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createUuidSchema } from "../types.js";
|
|
3
|
+
import { ISOTimestampFormatDescription } from "../utils/timestampInput.js";
|
|
4
|
+
export const TOOL_ARGS = {
|
|
5
|
+
cardholderQuery: z
|
|
6
|
+
.string()
|
|
7
|
+
.describe('The cardholder (person) to reconstruct, full-text name match, e.g. "Eve" or "Eve Adams".'),
|
|
8
|
+
locationUuids: z
|
|
9
|
+
.array(createUuidSchema())
|
|
10
|
+
.nullable()
|
|
11
|
+
.describe("Optional: restrict to these Rhombus location UUIDs. Use the location-tool to resolve names."),
|
|
12
|
+
startTime: z
|
|
13
|
+
.string()
|
|
14
|
+
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
|
|
15
|
+
.nullable()
|
|
16
|
+
.describe("Start of the window (inclusive). " + ISOTimestampFormatDescription),
|
|
17
|
+
endTime: z
|
|
18
|
+
.string()
|
|
19
|
+
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
|
|
20
|
+
.nullable()
|
|
21
|
+
.describe("End of the window (inclusive). " + ISOTimestampFormatDescription),
|
|
22
|
+
clipPaddingSeconds: z
|
|
23
|
+
.number()
|
|
24
|
+
.nullable()
|
|
25
|
+
.describe("Seconds of video before/after each badge tap to include in the clip hint (default 15)."),
|
|
26
|
+
limit: z.number().nullable().describe("Maximum badge taps to include (default 200)."),
|
|
27
|
+
timeZone: z
|
|
28
|
+
.string()
|
|
29
|
+
.nullable()
|
|
30
|
+
.describe("IANA timezone used to format times, e.g. America/New_York. Defaults to UTC."),
|
|
31
|
+
};
|
|
32
|
+
const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
|
|
33
|
+
const ClipHintSchema = z
|
|
34
|
+
.object({
|
|
35
|
+
deviceUuid: z.string(),
|
|
36
|
+
startTimeMs: z.number(),
|
|
37
|
+
endTimeMs: z.number(),
|
|
38
|
+
})
|
|
39
|
+
.describe("Pass to clips-tool createClip to get video of this tap.");
|
|
40
|
+
const StillHintSchema = z
|
|
41
|
+
.object({
|
|
42
|
+
deviceUuid: z.string(),
|
|
43
|
+
timestampMs: z.number(),
|
|
44
|
+
})
|
|
45
|
+
.describe("Pass to camera-tool (requestType image) to get a still of this tap.");
|
|
46
|
+
export const BadgeTimelineStopSchema = z.object({
|
|
47
|
+
timestampMs: z.number().optional(),
|
|
48
|
+
datetime: z.string().optional().describe("Human-readable tap time in the requested timezone."),
|
|
49
|
+
deviceUuid: z
|
|
50
|
+
.string()
|
|
51
|
+
.optional()
|
|
52
|
+
.describe("The camera at this door. Pass to camera-tool (image) or clips-tool (createClip)."),
|
|
53
|
+
area: z.string().optional().describe("The area entered (or exited) at this tap."),
|
|
54
|
+
label: z.string().optional(),
|
|
55
|
+
isAnomaly: z.boolean().optional().describe("True if this tap was an alerting/anomalous event."),
|
|
56
|
+
clipHint: ClipHintSchema.optional(),
|
|
57
|
+
stillHint: StillHintSchema.optional(),
|
|
58
|
+
gapToNextSeconds: z
|
|
59
|
+
.number()
|
|
60
|
+
.optional()
|
|
61
|
+
.describe("Seconds until the next tap — large gaps are unobserved movement between doors."),
|
|
62
|
+
});
|
|
63
|
+
export const OUTPUT_SCHEMA = z.object({
|
|
64
|
+
cardholderName: z.string().optional().describe("The resolved cardholder name."),
|
|
65
|
+
ambiguousCardholders: z
|
|
66
|
+
.array(z.string())
|
|
67
|
+
.optional()
|
|
68
|
+
.describe("Set when the query matched more than one person — disambiguate with the user before trusting the timeline."),
|
|
69
|
+
stops: z
|
|
70
|
+
.array(BadgeTimelineStopSchema)
|
|
71
|
+
.optional()
|
|
72
|
+
.describe("The cardholder's badge taps in chronological order (oldest first)."),
|
|
73
|
+
path: z.array(z.string()).optional().describe("Areas traversed, in order (consecutive repeats collapsed)."),
|
|
74
|
+
error: z.string().optional(),
|
|
75
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { createUuidSchema } from "../types.js";
|
|
3
|
+
import { ISOTimestampFormatDescription } from "../utils/timestampInput.js";
|
|
4
|
+
export const TOOL_ARGS = {
|
|
5
|
+
area: z
|
|
6
|
+
.string()
|
|
7
|
+
.nullable()
|
|
8
|
+
.describe('Filter to events whose entered area matches this, e.g. "back office". Full-text match.'),
|
|
9
|
+
locationUuids: z
|
|
10
|
+
.array(createUuidSchema())
|
|
11
|
+
.nullable()
|
|
12
|
+
.describe("Filter to these Rhombus location UUIDs. Use the location-tool to resolve names to UUIDs."),
|
|
13
|
+
deviceUuids: z
|
|
14
|
+
.array(createUuidSchema())
|
|
15
|
+
.nullable()
|
|
16
|
+
.describe("Filter to these camera UUIDs (the camera that saw the badge event)."),
|
|
17
|
+
cardholderQuery: z
|
|
18
|
+
.string()
|
|
19
|
+
.nullable()
|
|
20
|
+
.describe("Match the cardholder's name (full-text), e.g. a person you are looking for."),
|
|
21
|
+
badgeStatus: z.string().nullable().describe("Filter by badge status, e.g. Active or Lost."),
|
|
22
|
+
badgeType: z.string().nullable().describe("Filter by badge type."),
|
|
23
|
+
anomalyOnly: z
|
|
24
|
+
.boolean()
|
|
25
|
+
.nullable()
|
|
26
|
+
.describe("Only return anomaly events: an inactive/lost badge was used, or access was granted but no entry was made (possible tailgating)."),
|
|
27
|
+
entryMade: z
|
|
28
|
+
.boolean()
|
|
29
|
+
.nullable()
|
|
30
|
+
.describe("Filter by whether access was granted AND entry was actually made."),
|
|
31
|
+
startTime: z
|
|
32
|
+
.string()
|
|
33
|
+
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
|
|
34
|
+
.nullable()
|
|
35
|
+
.describe("Only events at or after this time (inclusive). " + ISOTimestampFormatDescription),
|
|
36
|
+
endTime: z
|
|
37
|
+
.string()
|
|
38
|
+
.datetime({ message: "Invalid datetime string. Expected ISO 8601 format.", offset: true })
|
|
39
|
+
.nullable()
|
|
40
|
+
.describe("Only events at or before this time (inclusive). " + ISOTimestampFormatDescription),
|
|
41
|
+
limit: z
|
|
42
|
+
.number()
|
|
43
|
+
.nullable()
|
|
44
|
+
.describe("Maximum number of events to return (default 200; the server caps at 1000)."),
|
|
45
|
+
timeZone: z
|
|
46
|
+
.string()
|
|
47
|
+
.nullable()
|
|
48
|
+
.describe("IANA timezone used to format event times, e.g. America/New_York. Defaults to UTC."),
|
|
49
|
+
};
|
|
50
|
+
const TOOL_ARGS_SCHEMA = z.object(TOOL_ARGS);
|
|
51
|
+
export const OnGuardEventSchema = z.object({
|
|
52
|
+
timestampMs: z.number().optional(),
|
|
53
|
+
datetime: z.string().optional().describe("Human-readable event time in the requested timezone."),
|
|
54
|
+
deviceUuid: z
|
|
55
|
+
.string()
|
|
56
|
+
.optional()
|
|
57
|
+
.describe("The camera that saw this event. Pass to camera-tool (requestType image) or clips-tool (createClip) to get a still/video."),
|
|
58
|
+
label: z.string().optional().describe('Event label, e.g. "OnGuard: Badge Authorized" or an anomaly label.'),
|
|
59
|
+
cardholderName: z.string().optional().describe("The cardholder (person) name."),
|
|
60
|
+
badgeStatus: z.string().optional(),
|
|
61
|
+
badgeType: z.string().optional(),
|
|
62
|
+
areaEntering: z.string().optional(),
|
|
63
|
+
areaExiting: z.string().optional(),
|
|
64
|
+
entryMade: z.boolean().optional(),
|
|
65
|
+
isAnomaly: z.boolean().optional().describe("True if this is an alerting/anomalous event."),
|
|
66
|
+
});
|
|
67
|
+
export const OUTPUT_SCHEMA = z.object({
|
|
68
|
+
events: z.array(OnGuardEventSchema).optional(),
|
|
69
|
+
error: z.string().optional(),
|
|
70
|
+
});
|
|
@@ -5855,6 +5855,12 @@ const Camera_GetCustomFootageSeekpointsV2WSRequest = z.object({
|
|
|
5855
5855
|
});
|
|
5856
5856
|
const SeekpointType = z.string();
|
|
5857
5857
|
const SeekpointIndexType = z.object({
|
|
5858
|
+
alert: z.boolean().optional(),
|
|
5859
|
+
areaEntering: z.string().optional(),
|
|
5860
|
+
areaExiting: z.string().optional(),
|
|
5861
|
+
badgeStatus: z.string().optional(),
|
|
5862
|
+
badgeType: z.string().optional(),
|
|
5863
|
+
entryMade: z.boolean().optional(),
|
|
5858
5864
|
compositComponentUuid: z.string().optional(),
|
|
5859
5865
|
customDescription: z.string().optional(),
|
|
5860
5866
|
customDisplayName: z.string().optional(),
|
|
@@ -10818,6 +10824,25 @@ const Eventsearch_GetEventSeekpointsWSResponse = z.object({
|
|
|
10818
10824
|
errorMsg: z.string().optional(),
|
|
10819
10825
|
warningMsg: z.string().optional()
|
|
10820
10826
|
});
|
|
10827
|
+
const Eventsearch_SearchOnGuardEventsWSRequest = z.object({
|
|
10828
|
+
afterMs: z.number().int().optional(),
|
|
10829
|
+
anomalyOnly: z.boolean().optional(),
|
|
10830
|
+
area: z.string().optional(),
|
|
10831
|
+
badgeStatus: z.string().optional(),
|
|
10832
|
+
badgeType: z.string().optional(),
|
|
10833
|
+
beforeMs: z.number().int().optional(),
|
|
10834
|
+
cardholderQuery: z.string().optional(),
|
|
10835
|
+
deviceUuids: z.array(z.string()).optional(),
|
|
10836
|
+
entryMade: z.boolean().optional(),
|
|
10837
|
+
limit: z.number().int().optional(),
|
|
10838
|
+
locationUuids: z.array(z.string()).optional()
|
|
10839
|
+
});
|
|
10840
|
+
const Eventsearch_SearchOnGuardEventsWSResponse = z.object({
|
|
10841
|
+
error: z.boolean().optional(),
|
|
10842
|
+
errorMsg: z.string().optional(),
|
|
10843
|
+
events: z.array(SeekpointIndexType).optional(),
|
|
10844
|
+
warningMsg: z.string().optional()
|
|
10845
|
+
});
|
|
10821
10846
|
const Export_ExportAuditEventsWSRequest = z.object({
|
|
10822
10847
|
endInterval: z.number().int().optional(),
|
|
10823
10848
|
excludeActions: z.array(z.string()).optional(),
|
|
@@ -21985,6 +22010,8 @@ export const schemas = {
|
|
|
21985
22010
|
Eventsearch_VideoFootageWSRequest,
|
|
21986
22011
|
Eventsearch_GetEventSeekpointsWSRequest,
|
|
21987
22012
|
Eventsearch_GetEventSeekpointsWSResponse,
|
|
22013
|
+
Eventsearch_SearchOnGuardEventsWSRequest,
|
|
22014
|
+
Eventsearch_SearchOnGuardEventsWSResponse,
|
|
21988
22015
|
Export_ExportAuditEventsWSRequest,
|
|
21989
22016
|
Export_ExportClimateEventsWSRequest,
|
|
21990
22017
|
Export_ExportCountReportsWSRequest,
|