openclaw-server 0.1.0
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/package.json +29 -0
- package/packs/default/faq.yaml +8 -0
- package/packs/default/intents.yaml +19 -0
- package/packs/default/pack.yaml +12 -0
- package/packs/default/policies.yaml +1 -0
- package/packs/default/scenarios.yaml +1 -0
- package/packs/default/synonyms.yaml +1 -0
- package/packs/default/templates.yaml +16 -0
- package/packs/default/tools.yaml +1 -0
- package/readme.md +1219 -0
- package/src/auth.ts +24 -0
- package/src/better-sqlite3.d.ts +17 -0
- package/src/config.ts +63 -0
- package/src/core/matcher.ts +214 -0
- package/src/core/normalizer.test.ts +37 -0
- package/src/core/normalizer.ts +183 -0
- package/src/core/pack-loader.ts +97 -0
- package/src/core/reply-engine.test.ts +76 -0
- package/src/core/reply-engine.ts +256 -0
- package/src/core/request-adapter.ts +65 -0
- package/src/core/session-store.ts +48 -0
- package/src/core/stream-renderer.ts +237 -0
- package/src/core/tool-engine.ts +60 -0
- package/src/debug-log.ts +211 -0
- package/src/index.ts +23 -0
- package/src/openai.ts +79 -0
- package/src/response-api.ts +107 -0
- package/src/routes/admin.ts +32 -0
- package/src/routes/chat-completions.ts +173 -0
- package/src/routes/health.ts +7 -0
- package/src/routes/models.ts +21 -0
- package/src/routes/request-validation.ts +33 -0
- package/src/routes/responses.ts +182 -0
- package/src/routes/tasks.ts +138 -0
- package/src/runtime-stats.ts +80 -0
- package/src/server.test.ts +776 -0
- package/src/server.ts +108 -0
- package/src/tasks/chat-integration.ts +70 -0
- package/src/tasks/service.ts +320 -0
- package/src/tasks/store.test.ts +183 -0
- package/src/tasks/store.ts +602 -0
- package/src/tasks/time-parser.test.ts +94 -0
- package/src/tasks/time-parser.ts +610 -0
- package/src/tasks/timezone.ts +171 -0
- package/src/tasks/types.ts +128 -0
- package/src/types.ts +202 -0
- package/src/weather/chat-integration.ts +56 -0
- package/src/weather/location-catalog.ts +166 -0
- package/src/weather/open-meteo-provider.ts +221 -0
- package/src/weather/parser.test.ts +23 -0
- package/src/weather/parser.ts +102 -0
- package/src/weather/service.test.ts +54 -0
- package/src/weather/service.ts +188 -0
- package/src/weather/types.ts +56 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import { requireBearerAuth } from "../auth.js";
|
|
3
|
+
import type { AppContext } from "../server.js";
|
|
4
|
+
|
|
5
|
+
export function registerModelsRoute(app: Express, context: AppContext): void {
|
|
6
|
+
app.get("/v1/models", (req, res) => {
|
|
7
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
8
|
+
context.recordAuthFailure();
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
res.json({
|
|
13
|
+
object: "list",
|
|
14
|
+
data: context.pack.manifest.models.map((id) => ({
|
|
15
|
+
id,
|
|
16
|
+
object: "model",
|
|
17
|
+
owned_by: "openclaw-server",
|
|
18
|
+
})),
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ToolDefinition, ToolChoice } from "../types.js";
|
|
2
|
+
|
|
3
|
+
function resolveRequestedToolName(toolChoice: ToolChoice | undefined): string | undefined {
|
|
4
|
+
if (!toolChoice || typeof toolChoice !== "object") {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
return toolChoice.function.name;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function validateToolChoice(params: {
|
|
11
|
+
tools: ToolDefinition[];
|
|
12
|
+
toolChoice: ToolChoice | undefined;
|
|
13
|
+
}): string | undefined {
|
|
14
|
+
const { tools, toolChoice } = params;
|
|
15
|
+
if (!toolChoice || toolChoice === "auto" || toolChoice === "none") {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
if (tools.length === 0) {
|
|
19
|
+
return "tool_choice was provided but no tools were supplied";
|
|
20
|
+
}
|
|
21
|
+
if (toolChoice === "required") {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const requestedName = resolveRequestedToolName(toolChoice);
|
|
26
|
+
if (!requestedName) {
|
|
27
|
+
return "tool_choice.function.name is required";
|
|
28
|
+
}
|
|
29
|
+
if (!tools.some((tool) => tool.function.name === requestedName)) {
|
|
30
|
+
return `tool_choice requested unknown tool: ${requestedName}`;
|
|
31
|
+
}
|
|
32
|
+
return undefined;
|
|
33
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import { requireBearerAuth } from "../auth.js";
|
|
3
|
+
import { normalizeRequest } from "../core/normalizer.js";
|
|
4
|
+
import { responseRequestToChatRequest } from "../core/request-adapter.js";
|
|
5
|
+
import { streamResponsesText, streamResponsesToolCall } from "../core/stream-renderer.js";
|
|
6
|
+
import {
|
|
7
|
+
logRequestDebug,
|
|
8
|
+
logResponseSelection,
|
|
9
|
+
logTaskInspection,
|
|
10
|
+
logWeatherInspection,
|
|
11
|
+
} from "../debug-log.js";
|
|
12
|
+
import {
|
|
13
|
+
buildResponsesResponse,
|
|
14
|
+
createResponseId,
|
|
15
|
+
createResponseOutputId,
|
|
16
|
+
} from "../response-api.js";
|
|
17
|
+
import type { AppContext } from "../server.js";
|
|
18
|
+
import { buildTaskEngineResult, inspectTaskMessage } from "../tasks/chat-integration.js";
|
|
19
|
+
import { ResponsesRequestSchema } from "../types.js";
|
|
20
|
+
import { inspectWeatherMessage, respondToWeatherMessage } from "../weather/chat-integration.js";
|
|
21
|
+
import { validateToolChoice } from "./request-validation.js";
|
|
22
|
+
|
|
23
|
+
export function registerResponsesRoute(app: Express, context: AppContext): void {
|
|
24
|
+
app.post("/v1/responses", async (req, res) => {
|
|
25
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
26
|
+
context.recordAuthFailure();
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const parsed = ResponsesRequestSchema.safeParse(req.body);
|
|
31
|
+
if (!parsed.success) {
|
|
32
|
+
const issue = parsed.error.issues[0];
|
|
33
|
+
res.status(400).json({
|
|
34
|
+
error: {
|
|
35
|
+
message: issue ? `${issue.path.join(".")}: ${issue.message}` : "Invalid request body",
|
|
36
|
+
type: "invalid_request_error",
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const toolChoiceError = validateToolChoice({
|
|
43
|
+
tools: parsed.data.tools ?? [],
|
|
44
|
+
toolChoice: parsed.data.tool_choice,
|
|
45
|
+
});
|
|
46
|
+
if (toolChoiceError) {
|
|
47
|
+
res.status(400).json({
|
|
48
|
+
error: {
|
|
49
|
+
message: toolChoiceError,
|
|
50
|
+
type: "invalid_request_error",
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const turn = normalizeRequest({
|
|
57
|
+
request: responseRequestToChatRequest(parsed.data),
|
|
58
|
+
defaultModelId: context.config.defaultModelId,
|
|
59
|
+
});
|
|
60
|
+
logRequestDebug({
|
|
61
|
+
enabled: context.config.debugLoggingEnabled,
|
|
62
|
+
route: "/v1/responses",
|
|
63
|
+
body: parsed.data,
|
|
64
|
+
turn,
|
|
65
|
+
previewChars: context.config.debugPreviewChars,
|
|
66
|
+
});
|
|
67
|
+
if (!turn.userText) {
|
|
68
|
+
logRequestDebug({
|
|
69
|
+
enabled: context.config.debugLoggingEnabled,
|
|
70
|
+
route: "/v1/responses",
|
|
71
|
+
body: parsed.data,
|
|
72
|
+
turn,
|
|
73
|
+
previewChars: context.config.debugPreviewChars,
|
|
74
|
+
note: "missing_user_text",
|
|
75
|
+
});
|
|
76
|
+
res.status(400).json({
|
|
77
|
+
error: {
|
|
78
|
+
message: "Missing user input in input.",
|
|
79
|
+
type: "invalid_request_error",
|
|
80
|
+
},
|
|
81
|
+
});
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const responseId = createResponseId();
|
|
86
|
+
const now = typeof req.body?.now === "string" ? req.body.now : undefined;
|
|
87
|
+
const taskMatch = inspectTaskMessage({
|
|
88
|
+
taskService: context.taskService,
|
|
89
|
+
turn,
|
|
90
|
+
explicitUser: parsed.data.user,
|
|
91
|
+
now,
|
|
92
|
+
});
|
|
93
|
+
logTaskInspection({
|
|
94
|
+
enabled: context.config.debugLoggingEnabled,
|
|
95
|
+
route: "/v1/responses",
|
|
96
|
+
userId: taskMatch.userId,
|
|
97
|
+
text: turn.userText,
|
|
98
|
+
inspection: taskMatch.inspection,
|
|
99
|
+
previewChars: context.config.debugPreviewChars,
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
const taskResult = taskMatch.inspection.shouldHandle
|
|
103
|
+
? buildTaskEngineResult({
|
|
104
|
+
turn,
|
|
105
|
+
taskResult: context.taskService.processMessage({
|
|
106
|
+
userId: taskMatch.userId,
|
|
107
|
+
text: turn.userText,
|
|
108
|
+
now,
|
|
109
|
+
}),
|
|
110
|
+
})
|
|
111
|
+
: undefined;
|
|
112
|
+
const weatherMatch = !taskResult
|
|
113
|
+
? inspectWeatherMessage({
|
|
114
|
+
weatherService: context.weatherService,
|
|
115
|
+
turn,
|
|
116
|
+
explicitUser: parsed.data.user,
|
|
117
|
+
})
|
|
118
|
+
: undefined;
|
|
119
|
+
if (weatherMatch) {
|
|
120
|
+
logWeatherInspection({
|
|
121
|
+
enabled: context.config.debugLoggingEnabled,
|
|
122
|
+
route: "/v1/responses",
|
|
123
|
+
userId: weatherMatch.userId,
|
|
124
|
+
text: turn.userText,
|
|
125
|
+
inspection: weatherMatch.inspection,
|
|
126
|
+
previewChars: context.config.debugPreviewChars,
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const weatherResult =
|
|
131
|
+
!taskResult && weatherMatch?.inspection.shouldHandle
|
|
132
|
+
? await respondToWeatherMessage({
|
|
133
|
+
weatherService: context.weatherService,
|
|
134
|
+
turn,
|
|
135
|
+
explicitUser: parsed.data.user,
|
|
136
|
+
})
|
|
137
|
+
: undefined;
|
|
138
|
+
const result = taskResult ?? weatherResult ?? context.replyEngine.respond(turn);
|
|
139
|
+
logResponseSelection({
|
|
140
|
+
enabled: context.config.debugLoggingEnabled,
|
|
141
|
+
route: "/v1/responses",
|
|
142
|
+
source: taskResult ? "task" : weatherResult ? "weather" : "reply",
|
|
143
|
+
finishReason: result.finishReason,
|
|
144
|
+
matchedIntentId: result.matchedIntentId,
|
|
145
|
+
templateId: result.templateId,
|
|
146
|
+
text: result.text,
|
|
147
|
+
previewChars: context.config.debugPreviewChars,
|
|
148
|
+
});
|
|
149
|
+
context.recordCompletion({
|
|
150
|
+
stream: turn.stream,
|
|
151
|
+
finishReason: result.finishReason,
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const outputItemId = createResponseOutputId(
|
|
155
|
+
result.finishReason === "tool_calls" ? "fc" : "msg",
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
if (!turn.stream) {
|
|
159
|
+
res.json(buildResponsesResponse({ id: responseId, result, outputItemId }));
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (result.finishReason === "tool_calls" && result.toolCalls?.length) {
|
|
164
|
+
await streamResponsesToolCall({
|
|
165
|
+
res,
|
|
166
|
+
id: responseId,
|
|
167
|
+
result,
|
|
168
|
+
outputItemId,
|
|
169
|
+
});
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
await streamResponsesText({
|
|
174
|
+
res,
|
|
175
|
+
id: responseId,
|
|
176
|
+
result,
|
|
177
|
+
outputItemId,
|
|
178
|
+
initialDelayMs: context.config.streamInitialDelayMs,
|
|
179
|
+
chunkChars: context.config.streamChunkChars,
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { Express } from "express";
|
|
2
|
+
import { requireBearerAuth } from "../auth.js";
|
|
3
|
+
import { logResponseSelection, logTaskInspection } from "../debug-log.js";
|
|
4
|
+
import type { AppContext } from "../server.js";
|
|
5
|
+
import {
|
|
6
|
+
TaskChatRequestSchema,
|
|
7
|
+
TaskListQuerySchema,
|
|
8
|
+
TaskReminderQuerySchema,
|
|
9
|
+
TaskStatsQuerySchema,
|
|
10
|
+
} from "../tasks/types.js";
|
|
11
|
+
|
|
12
|
+
function validationError(res: import("express").Response, issue?: { path: PropertyKey[]; message: string }) {
|
|
13
|
+
res.status(400).json({
|
|
14
|
+
error: {
|
|
15
|
+
message: issue ? `${issue.path.join(".")}: ${issue.message}` : "Invalid request",
|
|
16
|
+
type: "invalid_request_error",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function registerTaskRoutes(app: Express, context: AppContext): void {
|
|
22
|
+
app.post("/v1/tasks/chat", (req, res) => {
|
|
23
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
24
|
+
context.recordAuthFailure();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const parsed = TaskChatRequestSchema.safeParse(req.body);
|
|
29
|
+
if (!parsed.success) {
|
|
30
|
+
validationError(res, parsed.error.issues[0]);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const inspection = context.taskService.inspectMessage({
|
|
35
|
+
userId: parsed.data.user,
|
|
36
|
+
text: parsed.data.text,
|
|
37
|
+
now: parsed.data.now,
|
|
38
|
+
});
|
|
39
|
+
logTaskInspection({
|
|
40
|
+
enabled: context.config.debugLoggingEnabled,
|
|
41
|
+
route: "/v1/tasks/chat",
|
|
42
|
+
userId: parsed.data.user,
|
|
43
|
+
text: parsed.data.text,
|
|
44
|
+
inspection,
|
|
45
|
+
previewChars: context.config.debugPreviewChars,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = context.taskService.processMessage({
|
|
49
|
+
userId: parsed.data.user,
|
|
50
|
+
text: parsed.data.text,
|
|
51
|
+
now: parsed.data.now,
|
|
52
|
+
});
|
|
53
|
+
logResponseSelection({
|
|
54
|
+
enabled: context.config.debugLoggingEnabled,
|
|
55
|
+
route: "/v1/tasks/chat",
|
|
56
|
+
source: "task",
|
|
57
|
+
finishReason: "stop",
|
|
58
|
+
matchedIntentId: `task.${result.intent}`,
|
|
59
|
+
templateId: `task.${result.intent}`,
|
|
60
|
+
text: result.reply,
|
|
61
|
+
previewChars: context.config.debugPreviewChars,
|
|
62
|
+
});
|
|
63
|
+
res.json(result);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
app.get("/v1/tasks", (req, res) => {
|
|
67
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
68
|
+
context.recordAuthFailure();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const parsed = TaskListQuerySchema.safeParse({
|
|
73
|
+
user: typeof req.query.user === "string" ? req.query.user : undefined,
|
|
74
|
+
scope: typeof req.query.scope === "string" ? req.query.scope : undefined,
|
|
75
|
+
now: typeof req.query.now === "string" ? req.query.now : undefined,
|
|
76
|
+
});
|
|
77
|
+
if (!parsed.success) {
|
|
78
|
+
validationError(res, parsed.error.issues[0]);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const data = context.taskService.listTasks(
|
|
83
|
+
parsed.data.user,
|
|
84
|
+
parsed.data.scope ?? "today",
|
|
85
|
+
parsed.data.now,
|
|
86
|
+
);
|
|
87
|
+
res.json({ object: "list", data });
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
app.get("/v1/tasks/reminders/pending", (req, res) => {
|
|
91
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
92
|
+
context.recordAuthFailure();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const parsed = TaskReminderQuerySchema.safeParse({
|
|
97
|
+
user: typeof req.query.user === "string" ? req.query.user : undefined,
|
|
98
|
+
now: typeof req.query.now === "string" ? req.query.now : undefined,
|
|
99
|
+
});
|
|
100
|
+
if (!parsed.success) {
|
|
101
|
+
validationError(res, parsed.error.issues[0]);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const data = context.taskService.listPendingReminders(parsed.data.user, parsed.data.now);
|
|
106
|
+
res.json({ object: "list", data, count: data.length });
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
app.get("/v1/tasks/stats", (req, res) => {
|
|
110
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
111
|
+
context.recordAuthFailure();
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const parsed = TaskStatsQuerySchema.safeParse({
|
|
116
|
+
user: typeof req.query.user === "string" ? req.query.user : undefined,
|
|
117
|
+
now: typeof req.query.now === "string" ? req.query.now : undefined,
|
|
118
|
+
});
|
|
119
|
+
if (!parsed.success) {
|
|
120
|
+
validationError(res, parsed.error.issues[0]);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const data = context.taskService.getStats(parsed.data.user, parsed.data.now);
|
|
125
|
+
res.json({ object: "task.stats", data });
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
app.post("/admin/tasks/dispatch", (req, res) => {
|
|
129
|
+
if (!requireBearerAuth(req, res, context.config)) {
|
|
130
|
+
context.recordAuthFailure();
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const now = typeof req.body?.now === "string" ? req.body.now : undefined;
|
|
135
|
+
const dispatched = context.taskService.dispatchDueReminders(now);
|
|
136
|
+
res.json({ ok: true, dispatched });
|
|
137
|
+
});
|
|
138
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { SessionStore } from "./core/session-store.js";
|
|
2
|
+
import type { LoadedPack } from "./types.js";
|
|
3
|
+
|
|
4
|
+
export type RuntimeStatsSnapshot = {
|
|
5
|
+
startedAt: string;
|
|
6
|
+
lastRequestAt?: string;
|
|
7
|
+
lastReloadAt?: string;
|
|
8
|
+
requestsTotal: number;
|
|
9
|
+
streamedRequests: number;
|
|
10
|
+
textResponses: number;
|
|
11
|
+
toolCallResponses: number;
|
|
12
|
+
authFailures: number;
|
|
13
|
+
reloadCount: number;
|
|
14
|
+
activeSessions: number;
|
|
15
|
+
pack: {
|
|
16
|
+
id: string;
|
|
17
|
+
models: string[];
|
|
18
|
+
intents: number;
|
|
19
|
+
faqs: number;
|
|
20
|
+
scenarios: number;
|
|
21
|
+
templates: number;
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class RuntimeStats {
|
|
26
|
+
private readonly startedAt = new Date().toISOString();
|
|
27
|
+
private lastRequestAt?: string;
|
|
28
|
+
private lastReloadAt?: string;
|
|
29
|
+
private requestsTotal = 0;
|
|
30
|
+
private streamedRequests = 0;
|
|
31
|
+
private textResponses = 0;
|
|
32
|
+
private toolCallResponses = 0;
|
|
33
|
+
private authFailures = 0;
|
|
34
|
+
private reloadCount = 0;
|
|
35
|
+
|
|
36
|
+
recordAuthFailure(): void {
|
|
37
|
+
this.authFailures += 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
recordCompletion(params: { stream: boolean; finishReason: "stop" | "tool_calls" }): void {
|
|
41
|
+
this.requestsTotal += 1;
|
|
42
|
+
this.lastRequestAt = new Date().toISOString();
|
|
43
|
+
if (params.stream) {
|
|
44
|
+
this.streamedRequests += 1;
|
|
45
|
+
}
|
|
46
|
+
if (params.finishReason === "tool_calls") {
|
|
47
|
+
this.toolCallResponses += 1;
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
this.textResponses += 1;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
recordReload(): void {
|
|
54
|
+
this.reloadCount += 1;
|
|
55
|
+
this.lastReloadAt = new Date().toISOString();
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
snapshot(pack: LoadedPack, sessionStore: SessionStore): RuntimeStatsSnapshot {
|
|
59
|
+
return {
|
|
60
|
+
startedAt: this.startedAt,
|
|
61
|
+
lastRequestAt: this.lastRequestAt,
|
|
62
|
+
lastReloadAt: this.lastReloadAt,
|
|
63
|
+
requestsTotal: this.requestsTotal,
|
|
64
|
+
streamedRequests: this.streamedRequests,
|
|
65
|
+
textResponses: this.textResponses,
|
|
66
|
+
toolCallResponses: this.toolCallResponses,
|
|
67
|
+
authFailures: this.authFailures,
|
|
68
|
+
reloadCount: this.reloadCount,
|
|
69
|
+
activeSessions: sessionStore.size(),
|
|
70
|
+
pack: {
|
|
71
|
+
id: pack.manifest.id,
|
|
72
|
+
models: [...pack.manifest.models],
|
|
73
|
+
intents: pack.intents.length,
|
|
74
|
+
faqs: pack.faqs.length,
|
|
75
|
+
scenarios: pack.scenariosById.size,
|
|
76
|
+
templates: pack.templatesById.size,
|
|
77
|
+
},
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|