@harborclient/team-hub 0.4.2 → 0.4.3
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/cli.js +249 -18
- package/dist/cli.js.map +1 -1
- package/package.json +3 -1
package/dist/cli.js
CHANGED
|
@@ -21,9 +21,22 @@ import { Command as Command2 } from "commander";
|
|
|
21
21
|
|
|
22
22
|
// src/config/serverConfig.ts
|
|
23
23
|
import { existsSync, readFileSync } from "fs";
|
|
24
|
-
import
|
|
24
|
+
import path2 from "path";
|
|
25
25
|
import { parse as parseYaml } from "yaml";
|
|
26
26
|
|
|
27
|
+
// src/config/docsConfig.ts
|
|
28
|
+
import path from "path";
|
|
29
|
+
var DEFAULT_DOCS_SEARCH_INDEX_PATH = "/app/data/docsSearchIndex.json";
|
|
30
|
+
function resolveDocsSearchIndexPath(searchIndexPath) {
|
|
31
|
+
return path.isAbsolute(searchIndexPath) ? searchIndexPath : path.resolve(process.cwd(), searchIndexPath);
|
|
32
|
+
}
|
|
33
|
+
function normalizeDocsConfig(section) {
|
|
34
|
+
const trimmed = section.searchIndexPath?.trim();
|
|
35
|
+
return {
|
|
36
|
+
searchIndexPath: trimmed && trimmed.length > 0 ? trimmed : DEFAULT_DOCS_SEARCH_INDEX_PATH
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
// src/config/llmConfig.ts
|
|
28
41
|
function headerRowsFromSingleKeyObject(record) {
|
|
29
42
|
const rows = [];
|
|
@@ -176,6 +189,9 @@ var pluginsSectionSchema = z.object({
|
|
|
176
189
|
catalogs: z.array(z.string().trim().url()).optional(),
|
|
177
190
|
trusted: z.array(z.string().trim().url()).optional()
|
|
178
191
|
});
|
|
192
|
+
var docsSectionSchema = z.object({
|
|
193
|
+
searchIndexPath: z.string().trim().min(1).optional()
|
|
194
|
+
});
|
|
179
195
|
var logLevelSchema = z.enum(["debug", "info", "warn", "error"]);
|
|
180
196
|
var loggingSectionSchema = z.object({
|
|
181
197
|
level: logLevelSchema.optional(),
|
|
@@ -188,6 +204,7 @@ var serverConfigDocumentSchema = z.object({
|
|
|
188
204
|
redis: redisSectionSchema,
|
|
189
205
|
llm: llmSectionSchema.optional(),
|
|
190
206
|
plugins: pluginsSectionSchema.optional(),
|
|
207
|
+
docs: docsSectionSchema.optional(),
|
|
191
208
|
logging: loggingSectionSchema.optional()
|
|
192
209
|
});
|
|
193
210
|
|
|
@@ -205,7 +222,7 @@ var ConfigError = class extends Error {
|
|
|
205
222
|
}
|
|
206
223
|
};
|
|
207
224
|
function resolveConfigPath(configPath) {
|
|
208
|
-
return
|
|
225
|
+
return path2.isAbsolute(configPath) ? configPath : path2.resolve(process.cwd(), configPath);
|
|
209
226
|
}
|
|
210
227
|
function assertDocumentShape(document) {
|
|
211
228
|
if (document === null || typeof document !== "object" || Array.isArray(document)) {
|
|
@@ -288,6 +305,14 @@ function parseServerConfig(document) {
|
|
|
288
305
|
}
|
|
289
306
|
plugins = normalizePluginsConfig(parsedPluginsSection.data);
|
|
290
307
|
}
|
|
308
|
+
let docs = null;
|
|
309
|
+
if (root.docs !== void 0) {
|
|
310
|
+
const parsedDocsSection = docsSectionSchema.safeParse(root.docs);
|
|
311
|
+
if (!parsedDocsSection.success) {
|
|
312
|
+
throw new ConfigError(formatZodError(parsedDocsSection.error));
|
|
313
|
+
}
|
|
314
|
+
docs = normalizeDocsConfig(parsedDocsSection.data);
|
|
315
|
+
}
|
|
291
316
|
let logging = DEFAULT_LOGGING_CONFIG;
|
|
292
317
|
if (root.logging !== void 0) {
|
|
293
318
|
const parsedLoggingSection = loggingSectionSchema.safeParse(root.logging);
|
|
@@ -303,6 +328,7 @@ function parseServerConfig(document) {
|
|
|
303
328
|
redis: parsedRedisSection.data,
|
|
304
329
|
llm,
|
|
305
330
|
plugins,
|
|
331
|
+
docs,
|
|
306
332
|
logging
|
|
307
333
|
};
|
|
308
334
|
}
|
|
@@ -6470,6 +6496,14 @@ var LLM_MODEL_CATALOG = [
|
|
|
6470
6496
|
function hasProviderKey(config, provider) {
|
|
6471
6497
|
return Boolean(config.providers[provider]?.apiKey.trim());
|
|
6472
6498
|
}
|
|
6499
|
+
function hasHubOpenAiProvider(config) {
|
|
6500
|
+
return hasProviderKey(config, "openai");
|
|
6501
|
+
}
|
|
6502
|
+
function getHubLlmCapabilities(config) {
|
|
6503
|
+
return {
|
|
6504
|
+
openai: hasProviderKey(config, "openai")
|
|
6505
|
+
};
|
|
6506
|
+
}
|
|
6473
6507
|
function listHubOfferedModels(config) {
|
|
6474
6508
|
const allowList = config.models ? new Set(config.models) : null;
|
|
6475
6509
|
return LLM_MODEL_CATALOG.filter((model) => {
|
|
@@ -7285,8 +7319,12 @@ var llmModelSchema = z7.object({
|
|
|
7285
7319
|
label: z7.string(),
|
|
7286
7320
|
provider: z7.enum(["openai", "claude", "gemini"])
|
|
7287
7321
|
});
|
|
7322
|
+
var llmCapabilitiesSchema = z7.object({
|
|
7323
|
+
openai: z7.boolean()
|
|
7324
|
+
});
|
|
7288
7325
|
var listLlmModelsResponseSchema = z7.object({
|
|
7289
|
-
models: z7.array(llmModelSchema)
|
|
7326
|
+
models: z7.array(llmModelSchema),
|
|
7327
|
+
capabilities: llmCapabilitiesSchema
|
|
7290
7328
|
});
|
|
7291
7329
|
var llmUsageSummaryResponseSchema = z7.object({
|
|
7292
7330
|
period: z7.string(),
|
|
@@ -7637,7 +7675,7 @@ var listAdminTokensResponseSchema = z9.object({
|
|
|
7637
7675
|
tokens: z9.array(hubApiTokenRecordSchema)
|
|
7638
7676
|
});
|
|
7639
7677
|
var reloadConfigSectionResultSchema = z9.object({
|
|
7640
|
-
section: z9.enum(["db", "redis", "llm", "plugins", "server"]),
|
|
7678
|
+
section: z9.enum(["db", "redis", "llm", "plugins", "docs", "server"]),
|
|
7641
7679
|
status: z9.enum(["reloaded", "unchanged", "failed", "restart-required"]),
|
|
7642
7680
|
error: z9.string().optional()
|
|
7643
7681
|
});
|
|
@@ -8377,7 +8415,7 @@ async function registerAdminRoutes(app, options) {
|
|
|
8377
8415
|
label: model.label,
|
|
8378
8416
|
provider: model.provider
|
|
8379
8417
|
}));
|
|
8380
|
-
return reply.send({ models });
|
|
8418
|
+
return reply.send({ models, capabilities: getHubLlmCapabilities(llm) });
|
|
8381
8419
|
}
|
|
8382
8420
|
});
|
|
8383
8421
|
routes.route({
|
|
@@ -9832,6 +9870,165 @@ async function runLlmCompletion(config, input) {
|
|
|
9832
9870
|
return parseCompletionResponse(json);
|
|
9833
9871
|
}
|
|
9834
9872
|
|
|
9873
|
+
// src/server/docs/docsSearch.ts
|
|
9874
|
+
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "fs";
|
|
9875
|
+
import path3 from "path";
|
|
9876
|
+
import { create, load, search } from "@orama/orama";
|
|
9877
|
+
import OpenAI from "openai";
|
|
9878
|
+
var DOCS_EMBEDDING_MODEL = "text-embedding-3-small";
|
|
9879
|
+
var DOCS_EMBEDDING_DIMENSIONS = 1536;
|
|
9880
|
+
var DEFAULT_RESULT_LIMIT = 5;
|
|
9881
|
+
var MAX_RESULT_LIMIT = 10;
|
|
9882
|
+
var DEFAULT_SIMILARITY = 0.5;
|
|
9883
|
+
var SNIPPET_MAX_CHARS = 600;
|
|
9884
|
+
var DOCS_SEARCH_SCHEMA = {
|
|
9885
|
+
id: "string",
|
|
9886
|
+
source: "string",
|
|
9887
|
+
path: "string",
|
|
9888
|
+
url: "string",
|
|
9889
|
+
title: "string",
|
|
9890
|
+
heading: "string",
|
|
9891
|
+
content: "string",
|
|
9892
|
+
embedding: `vector[${DOCS_EMBEDDING_DIMENSIONS}]`
|
|
9893
|
+
};
|
|
9894
|
+
var cachedDb = null;
|
|
9895
|
+
var indexUnavailable = false;
|
|
9896
|
+
function getDocsSearchIndexPaths(docsConfig) {
|
|
9897
|
+
const paths = /* @__PURE__ */ new Set();
|
|
9898
|
+
if (docsConfig?.searchIndexPath) {
|
|
9899
|
+
paths.add(resolveDocsSearchIndexPath(docsConfig.searchIndexPath));
|
|
9900
|
+
}
|
|
9901
|
+
paths.add(DEFAULT_DOCS_SEARCH_INDEX_PATH);
|
|
9902
|
+
paths.add(path3.resolve(process.cwd(), "data/docsSearchIndex.json"));
|
|
9903
|
+
return [...paths];
|
|
9904
|
+
}
|
|
9905
|
+
function isDocsSearchIndexAvailable(docsConfig) {
|
|
9906
|
+
return getDocsSearchIndexPaths(docsConfig).some((candidate) => existsSync2(candidate));
|
|
9907
|
+
}
|
|
9908
|
+
function truncateSnippet(content, maxChars = SNIPPET_MAX_CHARS) {
|
|
9909
|
+
if (content.length <= maxChars) {
|
|
9910
|
+
return content;
|
|
9911
|
+
}
|
|
9912
|
+
return `${content.slice(0, maxChars)}...`;
|
|
9913
|
+
}
|
|
9914
|
+
function clampResultLimit(limit) {
|
|
9915
|
+
if (limit == null || !Number.isFinite(limit)) {
|
|
9916
|
+
return DEFAULT_RESULT_LIMIT;
|
|
9917
|
+
}
|
|
9918
|
+
return Math.min(Math.max(1, Math.floor(limit)), MAX_RESULT_LIMIT);
|
|
9919
|
+
}
|
|
9920
|
+
function loadDocsSearchIndex(docsConfig, paths) {
|
|
9921
|
+
if (cachedDb != null) {
|
|
9922
|
+
return cachedDb;
|
|
9923
|
+
}
|
|
9924
|
+
if (indexUnavailable) {
|
|
9925
|
+
throw new Error(
|
|
9926
|
+
"Documentation search index is not available. Deploy docsSearchIndex.json to the Team Hub server."
|
|
9927
|
+
);
|
|
9928
|
+
}
|
|
9929
|
+
const candidates = paths ?? getDocsSearchIndexPaths(docsConfig);
|
|
9930
|
+
const catalogPath = candidates.find((candidate) => existsSync2(candidate));
|
|
9931
|
+
if (catalogPath == null) {
|
|
9932
|
+
indexUnavailable = true;
|
|
9933
|
+
throw new Error(
|
|
9934
|
+
"Documentation search index is not available. Deploy docsSearchIndex.json to the Team Hub server."
|
|
9935
|
+
);
|
|
9936
|
+
}
|
|
9937
|
+
const raw = JSON.parse(readFileSync3(catalogPath, "utf8"));
|
|
9938
|
+
const db = create({ schema: DOCS_SEARCH_SCHEMA });
|
|
9939
|
+
load(db, raw);
|
|
9940
|
+
cachedDb = db;
|
|
9941
|
+
return db;
|
|
9942
|
+
}
|
|
9943
|
+
async function embedDocsQuery(query, apiKey) {
|
|
9944
|
+
const client = new OpenAI({ apiKey });
|
|
9945
|
+
const response = await client.embeddings.create({
|
|
9946
|
+
model: DOCS_EMBEDDING_MODEL,
|
|
9947
|
+
input: query
|
|
9948
|
+
});
|
|
9949
|
+
const embedding = response.data[0]?.embedding;
|
|
9950
|
+
if (!Array.isArray(embedding) || embedding.length !== DOCS_EMBEDDING_DIMENSIONS) {
|
|
9951
|
+
throw new Error("Unexpected embedding size from OpenAI.");
|
|
9952
|
+
}
|
|
9953
|
+
return embedding;
|
|
9954
|
+
}
|
|
9955
|
+
async function searchDocs(llmConfig, docsConfig, args) {
|
|
9956
|
+
const query = args.query?.trim();
|
|
9957
|
+
if (!query) {
|
|
9958
|
+
throw new Error("query is required.");
|
|
9959
|
+
}
|
|
9960
|
+
const apiKey = llmConfig.providers.openai?.apiKey.trim();
|
|
9961
|
+
if (!apiKey) {
|
|
9962
|
+
throw new Error(
|
|
9963
|
+
"OpenAI provider is not configured on this Team Hub. Documentation search requires an OpenAI API key."
|
|
9964
|
+
);
|
|
9965
|
+
}
|
|
9966
|
+
const db = loadDocsSearchIndex(docsConfig);
|
|
9967
|
+
const embedding = await embedDocsQuery(query, apiKey);
|
|
9968
|
+
const limit = clampResultLimit(args.limit);
|
|
9969
|
+
const results = search(db, {
|
|
9970
|
+
mode: "vector",
|
|
9971
|
+
vector: {
|
|
9972
|
+
value: embedding,
|
|
9973
|
+
property: "embedding"
|
|
9974
|
+
},
|
|
9975
|
+
similarity: DEFAULT_SIMILARITY,
|
|
9976
|
+
limit,
|
|
9977
|
+
...args.source != null ? { where: { source: args.source } } : {}
|
|
9978
|
+
});
|
|
9979
|
+
const resolved = results instanceof Promise ? await results : results;
|
|
9980
|
+
return resolved.hits.map((hit) => {
|
|
9981
|
+
const document = hit.document;
|
|
9982
|
+
return {
|
|
9983
|
+
title: document.title,
|
|
9984
|
+
heading: document.heading,
|
|
9985
|
+
url: document.url,
|
|
9986
|
+
source: document.source,
|
|
9987
|
+
path: document.path,
|
|
9988
|
+
score: hit.score,
|
|
9989
|
+
snippet: truncateSnippet(document.content)
|
|
9990
|
+
};
|
|
9991
|
+
});
|
|
9992
|
+
}
|
|
9993
|
+
|
|
9994
|
+
// src/server/llm/hubNativeTools.ts
|
|
9995
|
+
var HUB_NATIVE_TOOL_NAMES = ["search_docs"];
|
|
9996
|
+
function isHubNativeToolName(name) {
|
|
9997
|
+
return HUB_NATIVE_TOOL_NAMES.includes(name);
|
|
9998
|
+
}
|
|
9999
|
+
function canExecuteHubDocsSearch(llmConfig, docsConfig) {
|
|
10000
|
+
if (!llmConfig || !hasHubOpenAiProvider(llmConfig)) {
|
|
10001
|
+
return false;
|
|
10002
|
+
}
|
|
10003
|
+
return isDocsSearchIndexAvailable(docsConfig);
|
|
10004
|
+
}
|
|
10005
|
+
function filterClientToolsForHub(tools, llmConfig, docsConfig) {
|
|
10006
|
+
if (!tools || tools.length === 0) {
|
|
10007
|
+
return tools;
|
|
10008
|
+
}
|
|
10009
|
+
if (canExecuteHubDocsSearch(llmConfig, docsConfig)) {
|
|
10010
|
+
return tools;
|
|
10011
|
+
}
|
|
10012
|
+
const filtered = tools.filter((tool) => {
|
|
10013
|
+
const name = tool.function?.name;
|
|
10014
|
+
return name !== "search_docs";
|
|
10015
|
+
});
|
|
10016
|
+
return filtered.length > 0 ? filtered : void 0;
|
|
10017
|
+
}
|
|
10018
|
+
async function callHubNativeTool(name, args, llmConfig, docsConfig) {
|
|
10019
|
+
if (name !== "search_docs") {
|
|
10020
|
+
return JSON.stringify({ error: `Unknown hub-native tool: ${name}` });
|
|
10021
|
+
}
|
|
10022
|
+
try {
|
|
10023
|
+
const parsed = args;
|
|
10024
|
+
const hits = await searchDocs(llmConfig, docsConfig, parsed);
|
|
10025
|
+
return JSON.stringify(hits);
|
|
10026
|
+
} catch (error) {
|
|
10027
|
+
const message = error instanceof Error ? error.message : "Documentation search failed.";
|
|
10028
|
+
return JSON.stringify({ error: message });
|
|
10029
|
+
}
|
|
10030
|
+
}
|
|
10031
|
+
|
|
9835
10032
|
// src/server/llm/hubMcpToolNames.ts
|
|
9836
10033
|
var HUB_MCP_TOOL_PREFIX = "hubmcp__";
|
|
9837
10034
|
function encodeHubMcpToolName(serverIndex, toolName) {
|
|
@@ -10025,14 +10222,16 @@ function parseToolArguments(raw) {
|
|
|
10025
10222
|
return {};
|
|
10026
10223
|
}
|
|
10027
10224
|
}
|
|
10028
|
-
async function runHubChatStep(config, input, deps = {}) {
|
|
10225
|
+
async function runHubChatStep(config, input, deps = {}, docsConfig = null) {
|
|
10029
10226
|
const runCompletion = deps.runCompletion ?? runLlmCompletion;
|
|
10030
10227
|
const ensureConnections = deps.ensureConnections ?? ensureHubMcpConnections;
|
|
10031
10228
|
const listTools = deps.listTools ?? listHubMcpTools;
|
|
10032
10229
|
const callTool = deps.callTool ?? callHubMcpTool;
|
|
10230
|
+
const callNativeTool = deps.callNativeTool ?? callHubNativeTool;
|
|
10033
10231
|
await ensureConnections(config);
|
|
10034
10232
|
const hubTools = listTools();
|
|
10035
|
-
const
|
|
10233
|
+
const clientTools = filterClientToolsForHub(input.tools, config, docsConfig);
|
|
10234
|
+
const mergedTools = hubTools.length > 0 || (clientTools?.length ?? 0) > 0 ? [...hubTools, ...clientTools ?? []] : void 0;
|
|
10036
10235
|
let messages = [...input.messages];
|
|
10037
10236
|
let usage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
|
|
10038
10237
|
let lastContent = null;
|
|
@@ -10052,8 +10251,11 @@ async function runHubChatStep(config, input, deps = {}) {
|
|
|
10052
10251
|
usage
|
|
10053
10252
|
};
|
|
10054
10253
|
}
|
|
10254
|
+
const nativeCalls = toolCalls.filter((call) => isHubNativeToolName(call.name));
|
|
10055
10255
|
const hubCalls = toolCalls.filter((call) => isHubMcpToolName(call.name));
|
|
10056
|
-
const passthroughCalls = toolCalls.filter(
|
|
10256
|
+
const passthroughCalls = toolCalls.filter(
|
|
10257
|
+
(call) => !isHubNativeToolName(call.name) && !isHubMcpToolName(call.name)
|
|
10258
|
+
);
|
|
10057
10259
|
if (passthroughCalls.length > 0) {
|
|
10058
10260
|
return {
|
|
10059
10261
|
content: result.content,
|
|
@@ -10061,14 +10263,28 @@ async function runHubChatStep(config, input, deps = {}) {
|
|
|
10061
10263
|
usage
|
|
10062
10264
|
};
|
|
10063
10265
|
}
|
|
10266
|
+
const serverCalls = [...nativeCalls, ...hubCalls];
|
|
10064
10267
|
messages = [
|
|
10065
10268
|
...messages,
|
|
10066
10269
|
{
|
|
10067
10270
|
role: "assistant",
|
|
10068
10271
|
content: result.content,
|
|
10069
|
-
tool_calls:
|
|
10272
|
+
tool_calls: serverCalls
|
|
10070
10273
|
}
|
|
10071
10274
|
];
|
|
10275
|
+
for (const call of nativeCalls) {
|
|
10276
|
+
const toolResult = await callNativeTool(
|
|
10277
|
+
call.name,
|
|
10278
|
+
parseToolArguments(call.arguments),
|
|
10279
|
+
config,
|
|
10280
|
+
docsConfig
|
|
10281
|
+
);
|
|
10282
|
+
messages.push({
|
|
10283
|
+
role: "tool",
|
|
10284
|
+
tool_call_id: call.id,
|
|
10285
|
+
content: toolResult
|
|
10286
|
+
});
|
|
10287
|
+
}
|
|
10072
10288
|
for (const call of hubCalls) {
|
|
10073
10289
|
const toolResult = await callTool(call.name, parseToolArguments(call.arguments));
|
|
10074
10290
|
messages.push({
|
|
@@ -10127,7 +10343,8 @@ async function registerLlmRoutes(app, options) {
|
|
|
10127
10343
|
id: model.id,
|
|
10128
10344
|
label: model.label,
|
|
10129
10345
|
provider: model.provider
|
|
10130
|
-
}))
|
|
10346
|
+
})),
|
|
10347
|
+
capabilities: getHubLlmCapabilities(llm)
|
|
10131
10348
|
});
|
|
10132
10349
|
}
|
|
10133
10350
|
});
|
|
@@ -10201,12 +10418,17 @@ async function registerLlmRoutes(app, options) {
|
|
|
10201
10418
|
if (isNewTurn && isOverMonthlyLimit(totalTokens, user.llmMonthlyTokenLimit)) {
|
|
10202
10419
|
return sendMonthlyLimitExceeded(reply);
|
|
10203
10420
|
}
|
|
10204
|
-
const result = await runHubChatStep(
|
|
10205
|
-
|
|
10206
|
-
|
|
10207
|
-
|
|
10208
|
-
|
|
10209
|
-
|
|
10421
|
+
const result = await runHubChatStep(
|
|
10422
|
+
llm,
|
|
10423
|
+
{
|
|
10424
|
+
model,
|
|
10425
|
+
messages,
|
|
10426
|
+
tools,
|
|
10427
|
+
systemPrompt
|
|
10428
|
+
},
|
|
10429
|
+
{},
|
|
10430
|
+
options.getDocs()
|
|
10431
|
+
);
|
|
10210
10432
|
const catalogModel = getHubModelById(model);
|
|
10211
10433
|
if (!catalogModel) {
|
|
10212
10434
|
throw new Error(`Unknown hub model: ${model}`);
|
|
@@ -10353,7 +10575,11 @@ async function registerProtectedRoutes(app, options) {
|
|
|
10353
10575
|
await registerFolderRoutes(app, options.db);
|
|
10354
10576
|
await registerRequestRoutes(app, options.db);
|
|
10355
10577
|
await registerRunResultRoutes(app, options.db);
|
|
10356
|
-
await registerLlmRoutes(app, {
|
|
10578
|
+
await registerLlmRoutes(app, {
|
|
10579
|
+
db: options.db,
|
|
10580
|
+
getLlm: options.getLlm,
|
|
10581
|
+
getDocs: options.getDocs
|
|
10582
|
+
});
|
|
10357
10583
|
await registerPluginsRoutes(app, { getPlugins: options.getPlugins });
|
|
10358
10584
|
}
|
|
10359
10585
|
async function registerRoutes(app, options) {
|
|
@@ -10388,6 +10614,7 @@ async function createServer(ctxOrConfig, options = {}) {
|
|
|
10388
10614
|
throttleStore,
|
|
10389
10615
|
getLlm: ctx ? () => ctx.getLlm() : () => legacyConfig?.llm ?? null,
|
|
10390
10616
|
getPlugins: ctx ? () => ctx.getPlugins() : () => legacyConfig?.plugins ?? null,
|
|
10617
|
+
getDocs: ctx ? () => ctx.getDocs() : () => legacyConfig?.docs ?? null,
|
|
10391
10618
|
reloadConfig: options.reloadConfig ?? (async () => ({ sections: [] }))
|
|
10392
10619
|
});
|
|
10393
10620
|
return app;
|
|
@@ -10574,7 +10801,8 @@ function createRuntimeContext(config, configPath) {
|
|
|
10574
10801
|
dbHolder: { underlying: createDatabase(config.db) },
|
|
10575
10802
|
throttleHolder: { underlying: createThrottleStore(config.redis) },
|
|
10576
10803
|
llm: config.llm,
|
|
10577
|
-
plugins: config.plugins
|
|
10804
|
+
plugins: config.plugins,
|
|
10805
|
+
docs: config.docs
|
|
10578
10806
|
};
|
|
10579
10807
|
const ctx = {
|
|
10580
10808
|
configPath: state.configPath,
|
|
@@ -10588,6 +10816,7 @@ function createRuntimeContext(config, configPath) {
|
|
|
10588
10816
|
throttleStore: createSwappableProxy(state.throttleHolder),
|
|
10589
10817
|
getLlm: () => state.llm,
|
|
10590
10818
|
getPlugins: () => state.plugins,
|
|
10819
|
+
getDocs: () => state.docs,
|
|
10591
10820
|
logger: createLogger(config.logging)
|
|
10592
10821
|
};
|
|
10593
10822
|
runtimeContextStates.set(ctx, state);
|
|
@@ -10661,6 +10890,8 @@ async function reloadRuntimeConfig(ctx) {
|
|
|
10661
10890
|
sections.push({ section: "llm", status: "reloaded" });
|
|
10662
10891
|
state.plugins = nextConfig.plugins;
|
|
10663
10892
|
sections.push({ section: "plugins", status: "reloaded" });
|
|
10893
|
+
state.docs = nextConfig.docs;
|
|
10894
|
+
sections.push({ section: "docs", status: "reloaded" });
|
|
10664
10895
|
sections.push(reloadServerSection(state, nextConfig));
|
|
10665
10896
|
return { sections };
|
|
10666
10897
|
}
|