@f5xc-salesdemos/xcsh 18.19.2 → 18.20.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 +7 -7
- package/src/capability/skill.ts +1 -0
- package/src/extensibility/skills.ts +16 -0
- package/src/internal-urls/build-info.generated.ts +8 -8
- package/src/prompts/system/custom-system-prompt.md +3 -0
- package/src/prompts/system/system-prompt.md +4 -0
- package/src/sdk.ts +32 -0
- package/src/services/f5xc-knowledge.ts +177 -0
- package/src/system-prompt.ts +9 -2
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@f5xc-salesdemos/xcsh",
|
|
4
|
-
"version": "18.
|
|
4
|
+
"version": "18.20.0",
|
|
5
5
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
6
6
|
"homepage": "https://github.com/f5xc-salesdemos/xcsh",
|
|
7
7
|
"author": "Can Boluk",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@agentclientprotocol/sdk": "0.16.1",
|
|
49
49
|
"@mozilla/readability": "^0.6",
|
|
50
|
-
"@f5xc-salesdemos/xcsh-stats": "18.
|
|
51
|
-
"@f5xc-salesdemos/pi-agent-core": "18.
|
|
52
|
-
"@f5xc-salesdemos/pi-ai": "18.
|
|
53
|
-
"@f5xc-salesdemos/pi-natives": "18.
|
|
54
|
-
"@f5xc-salesdemos/pi-tui": "18.
|
|
55
|
-
"@f5xc-salesdemos/pi-utils": "18.
|
|
50
|
+
"@f5xc-salesdemos/xcsh-stats": "18.20.0",
|
|
51
|
+
"@f5xc-salesdemos/pi-agent-core": "18.20.0",
|
|
52
|
+
"@f5xc-salesdemos/pi-ai": "18.20.0",
|
|
53
|
+
"@f5xc-salesdemos/pi-natives": "18.20.0",
|
|
54
|
+
"@f5xc-salesdemos/pi-tui": "18.20.0",
|
|
55
|
+
"@f5xc-salesdemos/pi-utils": "18.20.0",
|
|
56
56
|
"@sinclair/typebox": "^0.34",
|
|
57
57
|
"@xterm/headless": "^6.0",
|
|
58
58
|
"ajv": "^8.18",
|
package/src/capability/skill.ts
CHANGED
|
@@ -14,6 +14,7 @@ export interface Skill {
|
|
|
14
14
|
filePath: string;
|
|
15
15
|
baseDir: string;
|
|
16
16
|
source: string;
|
|
17
|
+
contexts?: string[];
|
|
17
18
|
/** Source metadata for display */
|
|
18
19
|
_source?: SourceMeta;
|
|
19
20
|
}
|
|
@@ -56,6 +57,9 @@ export async function loadSkillsFromDir(options: LoadSkillsFromDirOptions): Prom
|
|
|
56
57
|
filePath: capSkill.path,
|
|
57
58
|
baseDir: capSkill.path.replace(/[\\/]SKILL\.md$/, ""),
|
|
58
59
|
source: options.source,
|
|
60
|
+
contexts: Array.isArray(capSkill.frontmatter?.contexts)
|
|
61
|
+
? (capSkill.frontmatter.contexts as string[])
|
|
62
|
+
: undefined,
|
|
59
63
|
_source: capSkill._source,
|
|
60
64
|
})),
|
|
61
65
|
warnings: (result.warnings ?? []).map(message => ({ skillPath: options.dir, message })),
|
|
@@ -170,6 +174,9 @@ export async function loadSkills(options: LoadSkillsOptions = {}): Promise<LoadS
|
|
|
170
174
|
filePath: capSkill.path,
|
|
171
175
|
baseDir: capSkill.path.replace(/[\\/]SKILL\.md$/, ""),
|
|
172
176
|
source: `${capSkill._source.provider}:${capSkill.level}`,
|
|
177
|
+
contexts: Array.isArray(capSkill.frontmatter?.contexts)
|
|
178
|
+
? (capSkill.frontmatter.contexts as string[])
|
|
179
|
+
: undefined,
|
|
173
180
|
_source: capSkill._source,
|
|
174
181
|
});
|
|
175
182
|
realPathSet.add(resolvedPath);
|
|
@@ -206,6 +213,9 @@ export async function loadSkills(options: LoadSkillsOptions = {}): Promise<LoadS
|
|
|
206
213
|
filePath: capSkill.path,
|
|
207
214
|
baseDir: capSkill.path.replace(/[\\/]SKILL\.md$/, ""),
|
|
208
215
|
source: "custom:user",
|
|
216
|
+
contexts: Array.isArray(capSkill.frontmatter?.contexts)
|
|
217
|
+
? (capSkill.frontmatter.contexts as string[])
|
|
218
|
+
: undefined,
|
|
209
219
|
_source: { ...capSkill._source, providerName: "Custom" },
|
|
210
220
|
},
|
|
211
221
|
path: capSkill.path,
|
|
@@ -250,3 +260,9 @@ export async function loadSkills(options: LoadSkillsOptions = {}): Promise<LoadS
|
|
|
250
260
|
warnings: [...(result.warnings ?? []).map(w => ({ skillPath: "", message: w })), ...collisionWarnings],
|
|
251
261
|
};
|
|
252
262
|
}
|
|
263
|
+
|
|
264
|
+
export function isApplicableToContext(skill: Skill, contextName?: string): boolean {
|
|
265
|
+
if (!skill.contexts || skill.contexts.length === 0) return true;
|
|
266
|
+
if (!contextName) return true;
|
|
267
|
+
return skill.contexts.includes(contextName);
|
|
268
|
+
}
|
|
@@ -17,17 +17,17 @@ export interface BuildInfo {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export const BUILD_INFO: BuildInfo = {
|
|
20
|
-
"version": "18.
|
|
21
|
-
"commit": "
|
|
22
|
-
"shortCommit": "
|
|
20
|
+
"version": "18.20.0",
|
|
21
|
+
"commit": "6feb4da2091180b8eb6488f3991608b55ce3e6a8",
|
|
22
|
+
"shortCommit": "6feb4da",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.
|
|
25
|
-
"commitDate": "2026-04-
|
|
26
|
-
"buildDate": "2026-04-
|
|
24
|
+
"tag": "v18.20.0",
|
|
25
|
+
"commitDate": "2026-04-28T04:58:55Z",
|
|
26
|
+
"buildDate": "2026-04-28T05:21:14.340Z",
|
|
27
27
|
"dirty": false,
|
|
28
28
|
"prNumber": "",
|
|
29
29
|
"repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
|
|
30
30
|
"repoSlug": "f5xc-salesdemos/xcsh",
|
|
31
|
-
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/
|
|
32
|
-
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.
|
|
31
|
+
"commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/6feb4da2091180b8eb6488f3991608b55ce3e6a8",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.20.0"
|
|
33
33
|
};
|
|
@@ -39,6 +39,9 @@ Credential source: {{context.credentialSource}}.
|
|
|
39
39
|
Auth status: {{context.authStatus}}.
|
|
40
40
|
All F5 XC operations should target this tenant and namespace unless explicitly told otherwise.
|
|
41
41
|
{{/if}}
|
|
42
|
+
{{#if knowledgeTopics}}
|
|
43
|
+
Available F5 XC documentation topics: {{knowledgeTopics}}.
|
|
44
|
+
{{/if}}
|
|
42
45
|
{{#if skills.length}}
|
|
43
46
|
Skills are specialized knowledge.
|
|
44
47
|
You **MUST** scan descriptions for your task domain.
|
|
@@ -143,6 +143,10 @@ Auth status: {{context.authStatus}}.
|
|
|
143
143
|
All F5 XC operations should target this tenant and namespace unless explicitly told otherwise.
|
|
144
144
|
{{/if}}
|
|
145
145
|
|
|
146
|
+
{{#if knowledgeTopics}}
|
|
147
|
+
Available F5 XC documentation topics: {{knowledgeTopics}}.
|
|
148
|
+
{{/if}}
|
|
149
|
+
|
|
146
150
|
{{#if contextFiles.length}}
|
|
147
151
|
<context>
|
|
148
152
|
Context files below **MUST** be followed for all tasks:
|
package/src/sdk.ts
CHANGED
|
@@ -738,6 +738,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
738
738
|
// Capture ContextService reference for sync consumers (e.g., InternalDocsProtocolHandler's
|
|
739
739
|
// getContextStatus getter below). Null when ContextService isn't available (SDK consumers, tests).
|
|
740
740
|
let contextServiceRef: typeof import("./services/f5xc-context").ContextService | null = null;
|
|
741
|
+
let knowledgeServiceRef: typeof import("./services/f5xc-knowledge").KnowledgeService | null = null;
|
|
741
742
|
|
|
742
743
|
// Capture ContextService reference for sync consumers (rebuildSystemPrompt context resolution,
|
|
743
744
|
// InternalDocsProtocolHandler getContextStatus). The context-change listener itself is
|
|
@@ -749,6 +750,17 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
749
750
|
} catch {
|
|
750
751
|
// ContextService not available (SDK consumers, tests). Skip.
|
|
751
752
|
}
|
|
753
|
+
try {
|
|
754
|
+
const { KnowledgeService } = await import("./services/f5xc-knowledge");
|
|
755
|
+
const { getF5XCConfigDir } = await import("@f5xc-salesdemos/pi-utils");
|
|
756
|
+
knowledgeServiceRef = KnowledgeService;
|
|
757
|
+
if (!KnowledgeService._hasInstance()) {
|
|
758
|
+
KnowledgeService.init(getF5XCConfigDir());
|
|
759
|
+
KnowledgeService.instance.loadCache();
|
|
760
|
+
}
|
|
761
|
+
} catch {
|
|
762
|
+
// KnowledgeService not available — skip.
|
|
763
|
+
}
|
|
752
764
|
|
|
753
765
|
// Check if session has existing data to restore
|
|
754
766
|
const existingSession = logger.time("loadSessionContext", () =>
|
|
@@ -1370,6 +1382,24 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1370
1382
|
// ContextService not available or not initialized — leave contextForPrompt undefined.
|
|
1371
1383
|
}
|
|
1372
1384
|
|
|
1385
|
+
let knowledgeTopics: string | undefined;
|
|
1386
|
+
try {
|
|
1387
|
+
if (knowledgeServiceRef) {
|
|
1388
|
+
const svc = knowledgeServiceRef.instance;
|
|
1389
|
+
const cached = svc.getIndex();
|
|
1390
|
+
if (cached && cached.products.length > 0) {
|
|
1391
|
+
knowledgeTopics = cached.products
|
|
1392
|
+
.map(p => p.name)
|
|
1393
|
+
.sort()
|
|
1394
|
+
.join(", ");
|
|
1395
|
+
}
|
|
1396
|
+
// Fire-and-forget background refresh when TTL is expired — never blocks the prompt.
|
|
1397
|
+
void svc.getOrRefreshIndex();
|
|
1398
|
+
}
|
|
1399
|
+
} catch {
|
|
1400
|
+
// KnowledgeService not available — leave undefined.
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1373
1403
|
// Build combined append prompt: memory instructions + MCP server instructions
|
|
1374
1404
|
const serverInstructions = mcpManager?.getServerInstructions();
|
|
1375
1405
|
let appendPrompt: string | undefined = memoryInstructions ?? undefined;
|
|
@@ -1406,6 +1436,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1406
1436
|
eagerTasks,
|
|
1407
1437
|
secretsEnabled,
|
|
1408
1438
|
context: contextForPrompt,
|
|
1439
|
+
knowledgeTopics,
|
|
1409
1440
|
});
|
|
1410
1441
|
|
|
1411
1442
|
if (options.systemPrompt === undefined) {
|
|
@@ -1430,6 +1461,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1430
1461
|
eagerTasks,
|
|
1431
1462
|
secretsEnabled,
|
|
1432
1463
|
context: contextForPrompt,
|
|
1464
|
+
knowledgeTopics,
|
|
1433
1465
|
});
|
|
1434
1466
|
}
|
|
1435
1467
|
return options.systemPrompt(defaultPrompt);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
import { logger } from "@f5xc-salesdemos/pi-utils";
|
|
4
|
+
|
|
5
|
+
export interface LlmsProduct {
|
|
6
|
+
name: string;
|
|
7
|
+
description: string;
|
|
8
|
+
url: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface LlmsIndex {
|
|
12
|
+
title: string;
|
|
13
|
+
description: string;
|
|
14
|
+
products: LlmsProduct[];
|
|
15
|
+
fetchedAt: string;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const INFRASTRUCTURE_SLUGS = new Set([
|
|
19
|
+
"docs-builder",
|
|
20
|
+
"docs-theme",
|
|
21
|
+
"docs-icons",
|
|
22
|
+
"devcontainer",
|
|
23
|
+
"xcsh",
|
|
24
|
+
"docs",
|
|
25
|
+
"cdn-simulator",
|
|
26
|
+
"origin-server",
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
const ENTRY_PATTERN = /^- \[([^\]]+)\]\(([^)]+)\):\s*(.+)$/;
|
|
30
|
+
|
|
31
|
+
function extractSlug(url: string): string | null {
|
|
32
|
+
try {
|
|
33
|
+
const pathname = new URL(url).pathname;
|
|
34
|
+
const segments = pathname.split("/").filter(Boolean);
|
|
35
|
+
return segments[0] ?? null;
|
|
36
|
+
} catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function parseLlmsTxt(content: string, now?: Date): LlmsIndex {
|
|
42
|
+
const lines = content.split("\n");
|
|
43
|
+
let title = "";
|
|
44
|
+
let description = "";
|
|
45
|
+
const products: LlmsProduct[] = [];
|
|
46
|
+
let inFederatedSites = false;
|
|
47
|
+
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const trimmed = line.trim();
|
|
50
|
+
|
|
51
|
+
if (!title && trimmed.startsWith("# ")) {
|
|
52
|
+
title = trimmed.slice(2).trim();
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!description && trimmed.startsWith("> ")) {
|
|
57
|
+
description = trimmed.slice(2).trim();
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (trimmed.startsWith("## ")) {
|
|
62
|
+
inFederatedSites = trimmed === "## Federated Sites";
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!inFederatedSites) continue;
|
|
67
|
+
|
|
68
|
+
const match = ENTRY_PATTERN.exec(trimmed);
|
|
69
|
+
if (!match) continue;
|
|
70
|
+
|
|
71
|
+
const [, name, url, desc] = match;
|
|
72
|
+
const slug = extractSlug(url);
|
|
73
|
+
if (slug && INFRASTRUCTURE_SLUGS.has(slug)) continue;
|
|
74
|
+
|
|
75
|
+
products.push({ name, description: desc, url });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
title,
|
|
80
|
+
description,
|
|
81
|
+
products,
|
|
82
|
+
fetchedAt: (now ?? new Date()).toISOString(),
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const ROOT_LLMS_URL = "https://f5xc-salesdemos.github.io/docs/llms.txt";
|
|
87
|
+
const DEFAULT_TTL_MS = 3_600_000;
|
|
88
|
+
|
|
89
|
+
export class KnowledgeService {
|
|
90
|
+
static #instance: KnowledgeService | null = null;
|
|
91
|
+
|
|
92
|
+
#configDir: string;
|
|
93
|
+
#index: LlmsIndex | null = null;
|
|
94
|
+
|
|
95
|
+
private constructor(configDir: string) {
|
|
96
|
+
this.#configDir = configDir;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
static init(configDir: string): KnowledgeService {
|
|
100
|
+
KnowledgeService.#instance = new KnowledgeService(configDir);
|
|
101
|
+
return KnowledgeService.#instance;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
static get instance(): KnowledgeService {
|
|
105
|
+
if (!KnowledgeService.#instance) {
|
|
106
|
+
throw new Error("KnowledgeService not initialized. Call KnowledgeService.init() first.");
|
|
107
|
+
}
|
|
108
|
+
return KnowledgeService.#instance;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
static _resetForTest(): void {
|
|
112
|
+
KnowledgeService.#instance = null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
static _hasInstance(): boolean {
|
|
116
|
+
return KnowledgeService.#instance !== null;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
get cachePath(): string {
|
|
120
|
+
return path.join(this.#configDir, "knowledge-cache.json");
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
loadCache(): void {
|
|
124
|
+
try {
|
|
125
|
+
if (!fs.existsSync(this.cachePath)) return;
|
|
126
|
+
const raw = fs.readFileSync(this.cachePath, "utf-8");
|
|
127
|
+
this.#index = JSON.parse(raw) as LlmsIndex;
|
|
128
|
+
} catch {
|
|
129
|
+
this.#index = null;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
saveCache(index: LlmsIndex): void {
|
|
134
|
+
try {
|
|
135
|
+
fs.mkdirSync(this.#configDir, { recursive: true });
|
|
136
|
+
fs.writeFileSync(this.cachePath, JSON.stringify(index, null, 2));
|
|
137
|
+
} catch (err) {
|
|
138
|
+
logger.debug("F5XC knowledge cache write failed", { error: String(err) });
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
getIndex(): LlmsIndex | null {
|
|
143
|
+
return this.#index;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
async refreshIndex(): Promise<LlmsIndex> {
|
|
147
|
+
const response = await fetch(ROOT_LLMS_URL, {
|
|
148
|
+
signal: AbortSignal.timeout(10_000),
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
throw new Error(`Failed to fetch llms.txt: HTTP ${response.status}`);
|
|
152
|
+
}
|
|
153
|
+
const content = await response.text();
|
|
154
|
+
const index = parseLlmsTxt(content);
|
|
155
|
+
this.#index = index;
|
|
156
|
+
this.saveCache(index);
|
|
157
|
+
return index;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
async getOrRefreshIndex(ttlMs = DEFAULT_TTL_MS): Promise<LlmsIndex | null> {
|
|
161
|
+
if (this.#index) {
|
|
162
|
+
const age = Date.now() - new Date(this.#index.fetchedAt).getTime();
|
|
163
|
+
if (age < ttlMs) return this.#index;
|
|
164
|
+
}
|
|
165
|
+
try {
|
|
166
|
+
return await this.refreshIndex();
|
|
167
|
+
} catch (err) {
|
|
168
|
+
logger.debug("F5XC knowledge index refresh failed, using stale cache", { error: String(err) });
|
|
169
|
+
return this.#index;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getProductNames(): string[] {
|
|
174
|
+
if (!this.#index) return [];
|
|
175
|
+
return this.#index.products.map(p => p.name).sort();
|
|
176
|
+
}
|
|
177
|
+
}
|
package/src/system-prompt.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { contextFileCapability } from "./capability/context-file";
|
|
|
12
12
|
import { systemPromptCapability } from "./capability/system-prompt";
|
|
13
13
|
import type { SkillsSettings } from "./config/settings";
|
|
14
14
|
import { type ContextFile, loadCapability, type SystemPrompt as SystemPromptFile } from "./discovery";
|
|
15
|
-
import { loadSkills, type Skill } from "./extensibility/skills";
|
|
15
|
+
import { isApplicableToContext, loadSkills, type Skill } from "./extensibility/skills";
|
|
16
16
|
import customSystemPromptTemplate from "./prompts/system/custom-system-prompt.md" with { type: "text" };
|
|
17
17
|
import systemPromptTemplate from "./prompts/system/system-prompt.md" with { type: "text" };
|
|
18
18
|
|
|
@@ -441,6 +441,7 @@ export interface BuildSystemPromptOptions {
|
|
|
441
441
|
credentialSource: string;
|
|
442
442
|
authStatus: string;
|
|
443
443
|
};
|
|
444
|
+
knowledgeTopics?: string;
|
|
444
445
|
}
|
|
445
446
|
|
|
446
447
|
/** Build the system prompt with tools, guidelines, and context */
|
|
@@ -584,6 +585,11 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
584
585
|
const hasRead = tools?.has("read");
|
|
585
586
|
const filteredSkills = hasRead ? skills : [];
|
|
586
587
|
|
|
588
|
+
// contexts values match the tenant label derived from the API URL hostname (first DNS label).
|
|
589
|
+
// Example: https://acme.console.ves.volterra.io → tenant "acme" → contexts: ["acme"]
|
|
590
|
+
const contextName = context?.tenant;
|
|
591
|
+
const contextFilteredSkills = filteredSkills.filter(s => isApplicableToContext(s, contextName));
|
|
592
|
+
|
|
587
593
|
const effectiveSystemPromptCustomization = dedupePromptSource(systemPromptCustomization, [
|
|
588
594
|
resolvedCustomPrompt,
|
|
589
595
|
resolvedAppendPrompt,
|
|
@@ -602,7 +608,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
602
608
|
environment,
|
|
603
609
|
contextFiles,
|
|
604
610
|
agentsMdSearch,
|
|
605
|
-
skills:
|
|
611
|
+
skills: contextFilteredSkills,
|
|
606
612
|
rules: rules ?? [],
|
|
607
613
|
alwaysApplyRules: injectedAlwaysApplyRules,
|
|
608
614
|
date,
|
|
@@ -616,6 +622,7 @@ export async function buildSystemPrompt(options: BuildSystemPromptOptions = {}):
|
|
|
616
622
|
eagerTasks,
|
|
617
623
|
secretsEnabled,
|
|
618
624
|
context,
|
|
625
|
+
knowledgeTopics: options.knowledgeTopics,
|
|
619
626
|
};
|
|
620
627
|
let rendered = prompt.render(resolvedCustomPrompt ? customSystemPromptTemplate : systemPromptTemplate, data);
|
|
621
628
|
|