@f5xc-salesdemos/xcsh 18.19.2 → 18.20.1
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 +3 -0
- package/src/sdk.ts +37 -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.1",
|
|
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.1",
|
|
51
|
+
"@f5xc-salesdemos/pi-agent-core": "18.20.1",
|
|
52
|
+
"@f5xc-salesdemos/pi-ai": "18.20.1",
|
|
53
|
+
"@f5xc-salesdemos/pi-natives": "18.20.1",
|
|
54
|
+
"@f5xc-salesdemos/pi-tui": "18.20.1",
|
|
55
|
+
"@f5xc-salesdemos/pi-utils": "18.20.1",
|
|
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.1",
|
|
21
|
+
"commit": "4f93bcfbc6d05064e30e472fb061aedbf30647e9",
|
|
22
|
+
"shortCommit": "4f93bcf",
|
|
23
23
|
"branch": "main",
|
|
24
|
-
"tag": "v18.
|
|
25
|
-
"commitDate": "2026-04-
|
|
26
|
-
"buildDate": "2026-04-
|
|
24
|
+
"tag": "v18.20.1",
|
|
25
|
+
"commitDate": "2026-04-28T05:55:43Z",
|
|
26
|
+
"buildDate": "2026-04-28T06:14:50.511Z",
|
|
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/4f93bcfbc6d05064e30e472fb061aedbf30647e9",
|
|
32
|
+
"releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v18.20.1"
|
|
33
33
|
};
|
|
@@ -38,6 +38,9 @@ You are currently connected to F5 XC tenant: {{context.tenant}}, namespace: {{co
|
|
|
38
38
|
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
|
+
{{#if knowledgeTopics}}
|
|
42
|
+
Available F5 XC documentation topics: {{knowledgeTopics}}.
|
|
43
|
+
{{/if}}
|
|
41
44
|
{{/if}}
|
|
42
45
|
{{#if skills.length}}
|
|
43
46
|
Skills are specialized knowledge.
|
|
@@ -141,6 +141,9 @@ You are currently connected to F5 XC tenant: {{context.tenant}}, namespace: {{co
|
|
|
141
141
|
Credential source: {{context.credentialSource}}.
|
|
142
142
|
Auth status: {{context.authStatus}}.
|
|
143
143
|
All F5 XC operations should target this tenant and namespace unless explicitly told otherwise.
|
|
144
|
+
{{#if knowledgeTopics}}
|
|
145
|
+
Available F5 XC documentation topics: {{knowledgeTopics}}.
|
|
146
|
+
{{/if}}
|
|
144
147
|
{{/if}}
|
|
145
148
|
|
|
146
149
|
{{#if contextFiles.length}}
|
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,28 @@ 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
|
+
let cached = svc.getIndex();
|
|
1390
|
+
if (!cached) {
|
|
1391
|
+
await svc.getOrRefreshIndex();
|
|
1392
|
+
cached = svc.getIndex();
|
|
1393
|
+
} else {
|
|
1394
|
+
void svc.getOrRefreshIndex();
|
|
1395
|
+
}
|
|
1396
|
+
if (cached && cached.products.length > 0) {
|
|
1397
|
+
knowledgeTopics = cached.products
|
|
1398
|
+
.map(p => p.name)
|
|
1399
|
+
.sort()
|
|
1400
|
+
.join(", ");
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
} catch {
|
|
1404
|
+
// KnowledgeService not available — leave undefined.
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1373
1407
|
// Build combined append prompt: memory instructions + MCP server instructions
|
|
1374
1408
|
const serverInstructions = mcpManager?.getServerInstructions();
|
|
1375
1409
|
let appendPrompt: string | undefined = memoryInstructions ?? undefined;
|
|
@@ -1406,6 +1440,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1406
1440
|
eagerTasks,
|
|
1407
1441
|
secretsEnabled,
|
|
1408
1442
|
context: contextForPrompt,
|
|
1443
|
+
knowledgeTopics,
|
|
1409
1444
|
});
|
|
1410
1445
|
|
|
1411
1446
|
if (options.systemPrompt === undefined) {
|
|
@@ -1430,6 +1465,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1430
1465
|
eagerTasks,
|
|
1431
1466
|
secretsEnabled,
|
|
1432
1467
|
context: contextForPrompt,
|
|
1468
|
+
knowledgeTopics,
|
|
1433
1469
|
});
|
|
1434
1470
|
}
|
|
1435
1471
|
return options.systemPrompt(defaultPrompt);
|
|
@@ -1777,6 +1813,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
|
|
|
1777
1813
|
attribution: "agent",
|
|
1778
1814
|
});
|
|
1779
1815
|
lastEmittedContext = { name: currentName, namespace: currentNamespace };
|
|
1816
|
+
void session.refreshBaseSystemPrompt();
|
|
1780
1817
|
} catch {
|
|
1781
1818
|
// ContextService.instance throws if not initialized; skip.
|
|
1782
1819
|
}
|
|
@@ -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
|
|