@dexto/core 1.2.5 → 1.3.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.
Files changed (136) hide show
  1. package/README.md +47 -13
  2. package/dist/agent/DextoAgent.cjs +92 -34
  3. package/dist/agent/DextoAgent.d.ts +3 -3
  4. package/dist/agent/DextoAgent.d.ts.map +1 -1
  5. package/dist/agent/DextoAgent.js +93 -36
  6. package/dist/agent/schemas.cjs +24 -20
  7. package/dist/agent/schemas.d.ts +111 -107
  8. package/dist/agent/schemas.d.ts.map +1 -1
  9. package/dist/agent/schemas.js +8 -4
  10. package/dist/agent/types.d.ts +0 -1
  11. package/dist/agent/types.d.ts.map +1 -1
  12. package/dist/approval/schemas.cjs +2 -1
  13. package/dist/approval/schemas.d.ts +21 -20
  14. package/dist/approval/schemas.d.ts.map +1 -1
  15. package/dist/approval/schemas.js +2 -1
  16. package/dist/context/manager.cjs +7 -0
  17. package/dist/context/manager.d.ts.map +1 -1
  18. package/dist/context/manager.js +7 -0
  19. package/dist/context/types.d.ts +6 -2
  20. package/dist/context/types.d.ts.map +1 -1
  21. package/dist/errors/types.cjs +1 -0
  22. package/dist/errors/types.d.ts +4 -2
  23. package/dist/errors/types.d.ts.map +1 -1
  24. package/dist/errors/types.js +1 -0
  25. package/dist/events/index.cjs +4 -1
  26. package/dist/events/index.d.ts +23 -52
  27. package/dist/events/index.d.ts.map +1 -1
  28. package/dist/events/index.js +4 -1
  29. package/dist/llm/formatters/openai.cjs +8 -1
  30. package/dist/llm/formatters/openai.d.ts.map +1 -1
  31. package/dist/llm/formatters/openai.js +8 -1
  32. package/dist/llm/tokenizer/openai.d.ts +8 -0
  33. package/dist/llm/tokenizer/openai.d.ts.map +1 -1
  34. package/dist/logger/v2/schemas.cjs +1 -1
  35. package/dist/logger/v2/schemas.js +1 -1
  36. package/dist/memory/index.cjs +2 -0
  37. package/dist/memory/index.d.ts +1 -1
  38. package/dist/memory/index.d.ts.map +1 -1
  39. package/dist/memory/index.js +3 -1
  40. package/dist/memory/schemas.cjs +10 -0
  41. package/dist/memory/schemas.d.ts +33 -4
  42. package/dist/memory/schemas.d.ts.map +1 -1
  43. package/dist/memory/schemas.js +9 -0
  44. package/dist/plugins/error-codes.cjs +1 -0
  45. package/dist/plugins/error-codes.d.ts +3 -1
  46. package/dist/plugins/error-codes.d.ts.map +1 -1
  47. package/dist/plugins/error-codes.js +1 -0
  48. package/dist/plugins/loader.cjs +25 -5
  49. package/dist/plugins/loader.d.ts.map +1 -1
  50. package/dist/plugins/loader.js +25 -5
  51. package/dist/prompts/index.cjs +6 -8
  52. package/dist/prompts/index.d.ts +2 -4
  53. package/dist/prompts/index.d.ts.map +1 -1
  54. package/dist/prompts/index.js +4 -6
  55. package/dist/prompts/prompt-manager.cjs +2 -4
  56. package/dist/prompts/prompt-manager.d.ts.map +1 -1
  57. package/dist/prompts/prompt-manager.js +2 -4
  58. package/dist/prompts/providers/config-prompt-provider.cjs +331 -0
  59. package/dist/prompts/providers/config-prompt-provider.d.ts +34 -0
  60. package/dist/prompts/providers/config-prompt-provider.d.ts.map +1 -0
  61. package/dist/prompts/providers/config-prompt-provider.js +308 -0
  62. package/dist/prompts/providers/custom-prompt-provider.cjs +2 -2
  63. package/dist/prompts/providers/custom-prompt-provider.d.ts +1 -1
  64. package/dist/prompts/providers/custom-prompt-provider.d.ts.map +1 -1
  65. package/dist/prompts/providers/custom-prompt-provider.js +2 -2
  66. package/dist/prompts/schemas.cjs +42 -23
  67. package/dist/prompts/schemas.d.ts +121 -12
  68. package/dist/prompts/schemas.d.ts.map +1 -1
  69. package/dist/prompts/schemas.js +39 -22
  70. package/dist/prompts/types.d.ts +1 -1
  71. package/dist/prompts/types.d.ts.map +1 -1
  72. package/dist/storage/cache/factory.cjs +6 -2
  73. package/dist/storage/cache/factory.d.ts +2 -1
  74. package/dist/storage/cache/factory.d.ts.map +1 -1
  75. package/dist/storage/cache/factory.js +6 -2
  76. package/dist/storage/database/factory.cjs +11 -17
  77. package/dist/storage/database/factory.d.ts +2 -1
  78. package/dist/storage/database/factory.d.ts.map +1 -1
  79. package/dist/storage/database/factory.js +11 -17
  80. package/dist/storage/database/sqlite-store.cjs +8 -0
  81. package/dist/storage/database/sqlite-store.d.ts.map +1 -1
  82. package/dist/storage/database/sqlite-store.js +8 -0
  83. package/dist/storage/error-codes.cjs +1 -0
  84. package/dist/storage/error-codes.d.ts +1 -0
  85. package/dist/storage/error-codes.d.ts.map +1 -1
  86. package/dist/storage/error-codes.js +1 -0
  87. package/dist/storage/errors.cjs +17 -0
  88. package/dist/storage/errors.d.ts +9 -0
  89. package/dist/storage/errors.d.ts.map +1 -1
  90. package/dist/storage/errors.js +17 -0
  91. package/dist/systemPrompt/in-built-prompts.cjs +0 -5
  92. package/dist/systemPrompt/in-built-prompts.d.ts +1 -2
  93. package/dist/systemPrompt/in-built-prompts.d.ts.map +1 -1
  94. package/dist/systemPrompt/in-built-prompts.js +0 -4
  95. package/dist/systemPrompt/manager.cjs +24 -19
  96. package/dist/systemPrompt/manager.d.ts +2 -2
  97. package/dist/systemPrompt/manager.d.ts.map +1 -1
  98. package/dist/systemPrompt/manager.js +24 -19
  99. package/dist/systemPrompt/registry.cjs +1 -2
  100. package/dist/systemPrompt/registry.d.ts +1 -1
  101. package/dist/systemPrompt/registry.d.ts.map +1 -1
  102. package/dist/systemPrompt/registry.js +1 -2
  103. package/dist/systemPrompt/schemas.cjs +3 -17
  104. package/dist/systemPrompt/schemas.d.ts +13 -189
  105. package/dist/systemPrompt/schemas.d.ts.map +1 -1
  106. package/dist/systemPrompt/schemas.js +3 -17
  107. package/dist/telemetry/error-codes.cjs +36 -0
  108. package/dist/telemetry/error-codes.d.ts +13 -0
  109. package/dist/telemetry/error-codes.d.ts.map +1 -0
  110. package/dist/telemetry/error-codes.js +13 -0
  111. package/dist/telemetry/errors.cjs +105 -0
  112. package/dist/telemetry/errors.d.ts +28 -0
  113. package/dist/telemetry/errors.d.ts.map +1 -0
  114. package/dist/telemetry/errors.js +82 -0
  115. package/dist/telemetry/telemetry.cjs +92 -26
  116. package/dist/telemetry/telemetry.d.ts +1 -1
  117. package/dist/telemetry/telemetry.d.ts.map +1 -1
  118. package/dist/telemetry/telemetry.js +74 -18
  119. package/dist/tools/schemas.cjs +1 -1
  120. package/dist/tools/schemas.js +1 -1
  121. package/dist/tools/types.d.ts +0 -11
  122. package/dist/tools/types.d.ts.map +1 -1
  123. package/dist/utils/schema.d.ts +6 -0
  124. package/dist/utils/schema.d.ts.map +1 -1
  125. package/dist/utils/service-initializer.cjs +1 -0
  126. package/dist/utils/service-initializer.d.ts.map +1 -1
  127. package/dist/utils/service-initializer.js +1 -0
  128. package/package.json +52 -14
  129. package/dist/prompts/providers/file-prompt-provider.cjs +0 -401
  130. package/dist/prompts/providers/file-prompt-provider.d.ts +0 -49
  131. package/dist/prompts/providers/file-prompt-provider.d.ts.map +0 -1
  132. package/dist/prompts/providers/file-prompt-provider.js +0 -378
  133. package/dist/prompts/providers/starter-prompt-provider.cjs +0 -172
  134. package/dist/prompts/providers/starter-prompt-provider.d.ts +0 -47
  135. package/dist/prompts/providers/starter-prompt-provider.d.ts.map +0 -1
  136. package/dist/prompts/providers/starter-prompt-provider.js +0 -149
@@ -0,0 +1,331 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var config_prompt_provider_exports = {};
20
+ __export(config_prompt_provider_exports, {
21
+ ConfigPromptProvider: () => ConfigPromptProvider
22
+ });
23
+ module.exports = __toCommonJS(config_prompt_provider_exports);
24
+ var import_types = require("../../logger/v2/types.js");
25
+ var import_errors = require("../errors.js");
26
+ var import_utils = require("../utils.js");
27
+ var import_name_validation = require("../name-validation.js");
28
+ var import_promises = require("fs/promises");
29
+ var import_fs = require("fs");
30
+ var import_path = require("path");
31
+ class ConfigPromptProvider {
32
+ prompts = [];
33
+ promptsCache = [];
34
+ promptContent = /* @__PURE__ */ new Map();
35
+ cacheValid = false;
36
+ logger;
37
+ constructor(agentConfig, logger) {
38
+ this.logger = logger.createChild(import_types.DextoLogComponent.PROMPT);
39
+ this.prompts = agentConfig.prompts;
40
+ this.buildPromptsCache();
41
+ }
42
+ getSource() {
43
+ return "config";
44
+ }
45
+ invalidateCache() {
46
+ this.cacheValid = false;
47
+ this.promptsCache = [];
48
+ this.promptContent.clear();
49
+ this.logger.debug("ConfigPromptProvider cache invalidated");
50
+ }
51
+ updateConfig(agentConfig) {
52
+ this.prompts = agentConfig.prompts;
53
+ this.invalidateCache();
54
+ this.buildPromptsCache();
55
+ }
56
+ async listPrompts(_cursor) {
57
+ if (!this.cacheValid) {
58
+ await this.buildPromptsCache();
59
+ }
60
+ return {
61
+ prompts: this.promptsCache
62
+ };
63
+ }
64
+ async getPrompt(name, args) {
65
+ if (!this.cacheValid) {
66
+ await this.buildPromptsCache();
67
+ }
68
+ const promptInfo = this.promptsCache.find((p) => p.name === name);
69
+ if (!promptInfo) {
70
+ throw import_errors.PromptError.notFound(name);
71
+ }
72
+ let content = this.promptContent.get(name);
73
+ if (!content) {
74
+ throw import_errors.PromptError.missingText();
75
+ }
76
+ content = this.applyArguments(content, args);
77
+ return {
78
+ description: promptInfo.description,
79
+ messages: [
80
+ {
81
+ role: "user",
82
+ content: {
83
+ type: "text",
84
+ text: content
85
+ }
86
+ }
87
+ ]
88
+ };
89
+ }
90
+ async getPromptDefinition(name) {
91
+ if (!this.cacheValid) {
92
+ await this.buildPromptsCache();
93
+ }
94
+ const promptInfo = this.promptsCache.find((p) => p.name === name);
95
+ if (!promptInfo) {
96
+ return null;
97
+ }
98
+ return {
99
+ name: promptInfo.name,
100
+ ...promptInfo.title && { title: promptInfo.title },
101
+ ...promptInfo.description && { description: promptInfo.description },
102
+ ...promptInfo.arguments && { arguments: promptInfo.arguments }
103
+ };
104
+ }
105
+ async buildPromptsCache() {
106
+ const cache = [];
107
+ const contentMap = /* @__PURE__ */ new Map();
108
+ for (const prompt of this.prompts) {
109
+ try {
110
+ if (prompt.type === "inline") {
111
+ const { info, content } = this.processInlinePrompt(prompt);
112
+ cache.push(info);
113
+ contentMap.set(info.name, content);
114
+ } else if (prompt.type === "file") {
115
+ const result = await this.processFilePrompt(prompt);
116
+ if (result) {
117
+ cache.push(result.info);
118
+ contentMap.set(result.info.name, result.content);
119
+ }
120
+ }
121
+ } catch (error) {
122
+ this.logger.warn(
123
+ `Failed to process prompt: ${error instanceof Error ? error.message : String(error)}`
124
+ );
125
+ }
126
+ }
127
+ cache.sort((a, b) => {
128
+ const priorityA = a.metadata?.priority ?? 0;
129
+ const priorityB = b.metadata?.priority ?? 0;
130
+ return priorityB - priorityA;
131
+ });
132
+ this.promptsCache = cache;
133
+ this.promptContent = contentMap;
134
+ this.cacheValid = true;
135
+ this.logger.debug(`Cached ${cache.length} config prompts`);
136
+ }
137
+ processInlinePrompt(prompt) {
138
+ const promptName = `config:${prompt.id}`;
139
+ const promptInfo = {
140
+ name: promptName,
141
+ title: prompt.title,
142
+ description: prompt.description,
143
+ source: "config",
144
+ metadata: {
145
+ type: "inline",
146
+ category: prompt.category,
147
+ priority: prompt.priority,
148
+ showInStarters: prompt.showInStarters,
149
+ originalId: prompt.id
150
+ }
151
+ };
152
+ return { info: promptInfo, content: prompt.prompt };
153
+ }
154
+ async processFilePrompt(prompt) {
155
+ const filePath = prompt.file;
156
+ if (!(0, import_fs.existsSync)(filePath)) {
157
+ this.logger.warn(`Prompt file not found: ${filePath}`);
158
+ return null;
159
+ }
160
+ try {
161
+ const resolvedDir = await (0, import_promises.realpath)((0, import_path.dirname)(filePath));
162
+ const resolvedFile = await (0, import_promises.realpath)(filePath);
163
+ const rel = (0, import_path.relative)(resolvedDir, resolvedFile);
164
+ if (rel.startsWith(".." + import_path.sep) || rel === "..") {
165
+ this.logger.warn(
166
+ `Skipping prompt file '${filePath}': path traversal attempt detected (resolved outside directory)`
167
+ );
168
+ return null;
169
+ }
170
+ } catch (realpathError) {
171
+ this.logger.warn(
172
+ `Skipping prompt file '${filePath}': unable to resolve path (${realpathError instanceof Error ? realpathError.message : String(realpathError)})`
173
+ );
174
+ return null;
175
+ }
176
+ try {
177
+ const rawContent = await (0, import_promises.readFile)(filePath, "utf-8");
178
+ const parsed = this.parseMarkdownPrompt(rawContent, filePath);
179
+ try {
180
+ (0, import_name_validation.assertValidPromptName)(parsed.id, {
181
+ context: `file prompt '${filePath}'`,
182
+ hint: "Use kebab-case in the 'id:' frontmatter field or file name."
183
+ });
184
+ } catch (validationError) {
185
+ this.logger.warn(
186
+ `Invalid prompt name in '${filePath}': ${validationError instanceof Error ? validationError.message : String(validationError)}`
187
+ );
188
+ return null;
189
+ }
190
+ const promptInfo = {
191
+ name: `config:${parsed.id}`,
192
+ title: parsed.title,
193
+ description: parsed.description,
194
+ source: "config",
195
+ ...parsed.arguments && { arguments: parsed.arguments },
196
+ metadata: {
197
+ type: "file",
198
+ filePath,
199
+ category: parsed.category,
200
+ priority: parsed.priority,
201
+ showInStarters: prompt.showInStarters,
202
+ originalId: parsed.id
203
+ }
204
+ };
205
+ return { info: promptInfo, content: parsed.content };
206
+ } catch (error) {
207
+ this.logger.warn(
208
+ `Failed to read prompt file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
209
+ );
210
+ return null;
211
+ }
212
+ }
213
+ parseMarkdownPrompt(rawContent, filePath) {
214
+ const lines = rawContent.trim().split("\n");
215
+ const fileName = filePath.split("/").pop()?.replace(/\.md$/, "") ?? "unknown";
216
+ let id = fileName;
217
+ let title = fileName;
218
+ let description = `File prompt: ${fileName}`;
219
+ let category;
220
+ let priority;
221
+ let argumentHint;
222
+ let contentBody;
223
+ if (lines[0]?.trim() === "---") {
224
+ let frontmatterEnd = 0;
225
+ for (let i = 1; i < lines.length; i++) {
226
+ if (lines[i]?.trim() === "---") {
227
+ frontmatterEnd = i;
228
+ break;
229
+ }
230
+ }
231
+ if (frontmatterEnd > 0) {
232
+ const frontmatterLines = lines.slice(1, frontmatterEnd);
233
+ contentBody = lines.slice(frontmatterEnd + 1).join("\n");
234
+ for (const line of frontmatterLines) {
235
+ const match = (key) => {
236
+ const regex = new RegExp(`${key}:\\s*(?:['"](.+)['"]|(.+))`);
237
+ const m = line.match(regex);
238
+ return m ? (m[1] || m[2] || "").trim() : null;
239
+ };
240
+ if (line.includes("id:")) {
241
+ const val = match("id");
242
+ if (val) id = val;
243
+ } else if (line.includes("title:")) {
244
+ const val = match("title");
245
+ if (val) title = val;
246
+ } else if (line.includes("description:")) {
247
+ const val = match("description");
248
+ if (val) description = val;
249
+ } else if (line.includes("category:")) {
250
+ const val = match("category");
251
+ if (val) category = val;
252
+ } else if (line.includes("priority:")) {
253
+ const val = match("priority");
254
+ if (val) priority = parseInt(val, 10);
255
+ } else if (line.includes("argument-hint:")) {
256
+ const val = match("argument-hint");
257
+ if (val) argumentHint = val;
258
+ }
259
+ }
260
+ } else {
261
+ contentBody = rawContent;
262
+ }
263
+ } else {
264
+ contentBody = rawContent;
265
+ }
266
+ if (title === fileName) {
267
+ for (const line of contentBody.trim().split("\n")) {
268
+ if (line.trim().startsWith("#")) {
269
+ title = line.trim().replace(/^#+\s*/, "");
270
+ break;
271
+ }
272
+ }
273
+ }
274
+ const parsedArguments = argumentHint ? this.parseArgumentHint(argumentHint) : void 0;
275
+ return {
276
+ id,
277
+ title,
278
+ description,
279
+ content: contentBody.trim(),
280
+ ...category !== void 0 && { category },
281
+ ...priority !== void 0 && { priority },
282
+ ...parsedArguments !== void 0 && { arguments: parsedArguments }
283
+ };
284
+ }
285
+ parseArgumentHint(hint) {
286
+ const args = [];
287
+ const argPattern = /\[([^\]]+)\]/g;
288
+ let match;
289
+ while ((match = argPattern.exec(hint)) !== null) {
290
+ const argText = match[1];
291
+ if (!argText) continue;
292
+ const isOptional = argText.endsWith("?");
293
+ const name = isOptional ? argText.slice(0, -1).trim() : argText.trim();
294
+ if (name) {
295
+ args.push({
296
+ name,
297
+ required: !isOptional
298
+ });
299
+ }
300
+ }
301
+ return args;
302
+ }
303
+ applyArguments(content, args) {
304
+ const detectionTarget = content.replaceAll("$$", "");
305
+ const usesPositionalPlaceholders = /\$[1-9](?!\d)/.test(detectionTarget) || detectionTarget.includes("$ARGUMENTS");
306
+ const expanded = (0, import_utils.expandPlaceholders)(content, args).trim();
307
+ if (!args || typeof args !== "object" || Object.keys(args).length === 0) {
308
+ return expanded;
309
+ }
310
+ if (!usesPositionalPlaceholders) {
311
+ if (args._context) {
312
+ const contextString = String(args._context);
313
+ return `${expanded}
314
+
315
+ Context: ${contextString}`;
316
+ }
317
+ const argEntries = Object.entries(args).filter(([key]) => !key.startsWith("_"));
318
+ if (argEntries.length > 0) {
319
+ const formattedArgs = argEntries.map(([key, value]) => `${key}: ${value}`).join(", ");
320
+ return `${expanded}
321
+
322
+ Arguments: ${formattedArgs}`;
323
+ }
324
+ }
325
+ return expanded;
326
+ }
327
+ }
328
+ // Annotate the CommonJS export names for ESM import in node:
329
+ 0 && (module.exports = {
330
+ ConfigPromptProvider
331
+ });
@@ -0,0 +1,34 @@
1
+ import type { PromptProvider, PromptDefinition, PromptListResult } from '../types.js';
2
+ import type { GetPromptResult } from '@modelcontextprotocol/sdk/types.js';
3
+ import type { ValidatedAgentConfig } from '../../agent/schemas.js';
4
+ import type { IDextoLogger } from '../../logger/v2/types.js';
5
+ /**
6
+ * Config Prompt Provider - Unified provider for prompts from agent configuration
7
+ *
8
+ * Handles both inline prompts (text defined directly in config) and file-based prompts
9
+ * (loaded from markdown files). This replaces the old StarterPromptProvider and
10
+ * FilePromptProvider with a single, unified approach.
11
+ *
12
+ * Prompts with showInStarters: true are displayed as clickable buttons in the WebUI.
13
+ */
14
+ export declare class ConfigPromptProvider implements PromptProvider {
15
+ private prompts;
16
+ private promptsCache;
17
+ private promptContent;
18
+ private cacheValid;
19
+ private logger;
20
+ constructor(agentConfig: ValidatedAgentConfig, logger: IDextoLogger);
21
+ getSource(): string;
22
+ invalidateCache(): void;
23
+ updateConfig(agentConfig: ValidatedAgentConfig): void;
24
+ listPrompts(_cursor?: string): Promise<PromptListResult>;
25
+ getPrompt(name: string, args?: Record<string, unknown>): Promise<GetPromptResult>;
26
+ getPromptDefinition(name: string): Promise<PromptDefinition | null>;
27
+ private buildPromptsCache;
28
+ private processInlinePrompt;
29
+ private processFilePrompt;
30
+ private parseMarkdownPrompt;
31
+ private parseArgumentHint;
32
+ private applyArguments;
33
+ }
34
+ //# sourceMappingURL=config-prompt-provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-prompt-provider.d.ts","sourceRoot":"","sources":["../../../src/prompts/providers/config-prompt-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAc,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClG,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAC1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAS7D;;;;;;;;GAQG;AACH,qBAAa,oBAAqB,YAAW,cAAc;IACvD,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,YAAY,CAAoB;IACxC,OAAO,CAAC,aAAa,CAAkC;IACvD,OAAO,CAAC,UAAU,CAAkB;IACpC,OAAO,CAAC,MAAM,CAAe;gBAEjB,WAAW,EAAE,oBAAoB,EAAE,MAAM,EAAE,YAAY;IAMnE,SAAS,IAAI,MAAM;IAInB,eAAe,IAAI,IAAI;IAOvB,YAAY,CAAC,WAAW,EAAE,oBAAoB,GAAG,IAAI;IAM/C,WAAW,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAUxD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,eAAe,CAAC;IAgCjF,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC;YAkB3D,iBAAiB;IAsC/B,OAAO,CAAC,mBAAmB;YAsBb,iBAAiB;IAwE/B,OAAO,CAAC,mBAAmB;IA+F3B,OAAO,CAAC,iBAAiB;IAyBzB,OAAO,CAAC,cAAc;CA+BzB"}
@@ -0,0 +1,308 @@
1
+ import "../../chunk-C6A6W6XS.js";
2
+ import { DextoLogComponent } from "../../logger/v2/types.js";
3
+ import { PromptError } from "../errors.js";
4
+ import { expandPlaceholders } from "../utils.js";
5
+ import { assertValidPromptName } from "../name-validation.js";
6
+ import { readFile, realpath } from "fs/promises";
7
+ import { existsSync } from "fs";
8
+ import { dirname, relative, sep } from "path";
9
+ class ConfigPromptProvider {
10
+ prompts = [];
11
+ promptsCache = [];
12
+ promptContent = /* @__PURE__ */ new Map();
13
+ cacheValid = false;
14
+ logger;
15
+ constructor(agentConfig, logger) {
16
+ this.logger = logger.createChild(DextoLogComponent.PROMPT);
17
+ this.prompts = agentConfig.prompts;
18
+ this.buildPromptsCache();
19
+ }
20
+ getSource() {
21
+ return "config";
22
+ }
23
+ invalidateCache() {
24
+ this.cacheValid = false;
25
+ this.promptsCache = [];
26
+ this.promptContent.clear();
27
+ this.logger.debug("ConfigPromptProvider cache invalidated");
28
+ }
29
+ updateConfig(agentConfig) {
30
+ this.prompts = agentConfig.prompts;
31
+ this.invalidateCache();
32
+ this.buildPromptsCache();
33
+ }
34
+ async listPrompts(_cursor) {
35
+ if (!this.cacheValid) {
36
+ await this.buildPromptsCache();
37
+ }
38
+ return {
39
+ prompts: this.promptsCache
40
+ };
41
+ }
42
+ async getPrompt(name, args) {
43
+ if (!this.cacheValid) {
44
+ await this.buildPromptsCache();
45
+ }
46
+ const promptInfo = this.promptsCache.find((p) => p.name === name);
47
+ if (!promptInfo) {
48
+ throw PromptError.notFound(name);
49
+ }
50
+ let content = this.promptContent.get(name);
51
+ if (!content) {
52
+ throw PromptError.missingText();
53
+ }
54
+ content = this.applyArguments(content, args);
55
+ return {
56
+ description: promptInfo.description,
57
+ messages: [
58
+ {
59
+ role: "user",
60
+ content: {
61
+ type: "text",
62
+ text: content
63
+ }
64
+ }
65
+ ]
66
+ };
67
+ }
68
+ async getPromptDefinition(name) {
69
+ if (!this.cacheValid) {
70
+ await this.buildPromptsCache();
71
+ }
72
+ const promptInfo = this.promptsCache.find((p) => p.name === name);
73
+ if (!promptInfo) {
74
+ return null;
75
+ }
76
+ return {
77
+ name: promptInfo.name,
78
+ ...promptInfo.title && { title: promptInfo.title },
79
+ ...promptInfo.description && { description: promptInfo.description },
80
+ ...promptInfo.arguments && { arguments: promptInfo.arguments }
81
+ };
82
+ }
83
+ async buildPromptsCache() {
84
+ const cache = [];
85
+ const contentMap = /* @__PURE__ */ new Map();
86
+ for (const prompt of this.prompts) {
87
+ try {
88
+ if (prompt.type === "inline") {
89
+ const { info, content } = this.processInlinePrompt(prompt);
90
+ cache.push(info);
91
+ contentMap.set(info.name, content);
92
+ } else if (prompt.type === "file") {
93
+ const result = await this.processFilePrompt(prompt);
94
+ if (result) {
95
+ cache.push(result.info);
96
+ contentMap.set(result.info.name, result.content);
97
+ }
98
+ }
99
+ } catch (error) {
100
+ this.logger.warn(
101
+ `Failed to process prompt: ${error instanceof Error ? error.message : String(error)}`
102
+ );
103
+ }
104
+ }
105
+ cache.sort((a, b) => {
106
+ const priorityA = a.metadata?.priority ?? 0;
107
+ const priorityB = b.metadata?.priority ?? 0;
108
+ return priorityB - priorityA;
109
+ });
110
+ this.promptsCache = cache;
111
+ this.promptContent = contentMap;
112
+ this.cacheValid = true;
113
+ this.logger.debug(`Cached ${cache.length} config prompts`);
114
+ }
115
+ processInlinePrompt(prompt) {
116
+ const promptName = `config:${prompt.id}`;
117
+ const promptInfo = {
118
+ name: promptName,
119
+ title: prompt.title,
120
+ description: prompt.description,
121
+ source: "config",
122
+ metadata: {
123
+ type: "inline",
124
+ category: prompt.category,
125
+ priority: prompt.priority,
126
+ showInStarters: prompt.showInStarters,
127
+ originalId: prompt.id
128
+ }
129
+ };
130
+ return { info: promptInfo, content: prompt.prompt };
131
+ }
132
+ async processFilePrompt(prompt) {
133
+ const filePath = prompt.file;
134
+ if (!existsSync(filePath)) {
135
+ this.logger.warn(`Prompt file not found: ${filePath}`);
136
+ return null;
137
+ }
138
+ try {
139
+ const resolvedDir = await realpath(dirname(filePath));
140
+ const resolvedFile = await realpath(filePath);
141
+ const rel = relative(resolvedDir, resolvedFile);
142
+ if (rel.startsWith(".." + sep) || rel === "..") {
143
+ this.logger.warn(
144
+ `Skipping prompt file '${filePath}': path traversal attempt detected (resolved outside directory)`
145
+ );
146
+ return null;
147
+ }
148
+ } catch (realpathError) {
149
+ this.logger.warn(
150
+ `Skipping prompt file '${filePath}': unable to resolve path (${realpathError instanceof Error ? realpathError.message : String(realpathError)})`
151
+ );
152
+ return null;
153
+ }
154
+ try {
155
+ const rawContent = await readFile(filePath, "utf-8");
156
+ const parsed = this.parseMarkdownPrompt(rawContent, filePath);
157
+ try {
158
+ assertValidPromptName(parsed.id, {
159
+ context: `file prompt '${filePath}'`,
160
+ hint: "Use kebab-case in the 'id:' frontmatter field or file name."
161
+ });
162
+ } catch (validationError) {
163
+ this.logger.warn(
164
+ `Invalid prompt name in '${filePath}': ${validationError instanceof Error ? validationError.message : String(validationError)}`
165
+ );
166
+ return null;
167
+ }
168
+ const promptInfo = {
169
+ name: `config:${parsed.id}`,
170
+ title: parsed.title,
171
+ description: parsed.description,
172
+ source: "config",
173
+ ...parsed.arguments && { arguments: parsed.arguments },
174
+ metadata: {
175
+ type: "file",
176
+ filePath,
177
+ category: parsed.category,
178
+ priority: parsed.priority,
179
+ showInStarters: prompt.showInStarters,
180
+ originalId: parsed.id
181
+ }
182
+ };
183
+ return { info: promptInfo, content: parsed.content };
184
+ } catch (error) {
185
+ this.logger.warn(
186
+ `Failed to read prompt file ${filePath}: ${error instanceof Error ? error.message : String(error)}`
187
+ );
188
+ return null;
189
+ }
190
+ }
191
+ parseMarkdownPrompt(rawContent, filePath) {
192
+ const lines = rawContent.trim().split("\n");
193
+ const fileName = filePath.split("/").pop()?.replace(/\.md$/, "") ?? "unknown";
194
+ let id = fileName;
195
+ let title = fileName;
196
+ let description = `File prompt: ${fileName}`;
197
+ let category;
198
+ let priority;
199
+ let argumentHint;
200
+ let contentBody;
201
+ if (lines[0]?.trim() === "---") {
202
+ let frontmatterEnd = 0;
203
+ for (let i = 1; i < lines.length; i++) {
204
+ if (lines[i]?.trim() === "---") {
205
+ frontmatterEnd = i;
206
+ break;
207
+ }
208
+ }
209
+ if (frontmatterEnd > 0) {
210
+ const frontmatterLines = lines.slice(1, frontmatterEnd);
211
+ contentBody = lines.slice(frontmatterEnd + 1).join("\n");
212
+ for (const line of frontmatterLines) {
213
+ const match = (key) => {
214
+ const regex = new RegExp(`${key}:\\s*(?:['"](.+)['"]|(.+))`);
215
+ const m = line.match(regex);
216
+ return m ? (m[1] || m[2] || "").trim() : null;
217
+ };
218
+ if (line.includes("id:")) {
219
+ const val = match("id");
220
+ if (val) id = val;
221
+ } else if (line.includes("title:")) {
222
+ const val = match("title");
223
+ if (val) title = val;
224
+ } else if (line.includes("description:")) {
225
+ const val = match("description");
226
+ if (val) description = val;
227
+ } else if (line.includes("category:")) {
228
+ const val = match("category");
229
+ if (val) category = val;
230
+ } else if (line.includes("priority:")) {
231
+ const val = match("priority");
232
+ if (val) priority = parseInt(val, 10);
233
+ } else if (line.includes("argument-hint:")) {
234
+ const val = match("argument-hint");
235
+ if (val) argumentHint = val;
236
+ }
237
+ }
238
+ } else {
239
+ contentBody = rawContent;
240
+ }
241
+ } else {
242
+ contentBody = rawContent;
243
+ }
244
+ if (title === fileName) {
245
+ for (const line of contentBody.trim().split("\n")) {
246
+ if (line.trim().startsWith("#")) {
247
+ title = line.trim().replace(/^#+\s*/, "");
248
+ break;
249
+ }
250
+ }
251
+ }
252
+ const parsedArguments = argumentHint ? this.parseArgumentHint(argumentHint) : void 0;
253
+ return {
254
+ id,
255
+ title,
256
+ description,
257
+ content: contentBody.trim(),
258
+ ...category !== void 0 && { category },
259
+ ...priority !== void 0 && { priority },
260
+ ...parsedArguments !== void 0 && { arguments: parsedArguments }
261
+ };
262
+ }
263
+ parseArgumentHint(hint) {
264
+ const args = [];
265
+ const argPattern = /\[([^\]]+)\]/g;
266
+ let match;
267
+ while ((match = argPattern.exec(hint)) !== null) {
268
+ const argText = match[1];
269
+ if (!argText) continue;
270
+ const isOptional = argText.endsWith("?");
271
+ const name = isOptional ? argText.slice(0, -1).trim() : argText.trim();
272
+ if (name) {
273
+ args.push({
274
+ name,
275
+ required: !isOptional
276
+ });
277
+ }
278
+ }
279
+ return args;
280
+ }
281
+ applyArguments(content, args) {
282
+ const detectionTarget = content.replaceAll("$$", "");
283
+ const usesPositionalPlaceholders = /\$[1-9](?!\d)/.test(detectionTarget) || detectionTarget.includes("$ARGUMENTS");
284
+ const expanded = expandPlaceholders(content, args).trim();
285
+ if (!args || typeof args !== "object" || Object.keys(args).length === 0) {
286
+ return expanded;
287
+ }
288
+ if (!usesPositionalPlaceholders) {
289
+ if (args._context) {
290
+ const contextString = String(args._context);
291
+ return `${expanded}
292
+
293
+ Context: ${contextString}`;
294
+ }
295
+ const argEntries = Object.entries(args).filter(([key]) => !key.startsWith("_"));
296
+ if (argEntries.length > 0) {
297
+ const formattedArgs = argEntries.map(([key, value]) => `${key}: ${value}`).join(", ");
298
+ return `${expanded}
299
+
300
+ Arguments: ${formattedArgs}`;
301
+ }
302
+ }
303
+ return expanded;
304
+ }
305
+ }
306
+ export {
307
+ ConfigPromptProvider
308
+ };
@@ -134,8 +134,8 @@ class CustomPromptProvider {
134
134
  if (input.resource) {
135
135
  try {
136
136
  const blobService = this.resourceManager.getBlobStore();
137
- const { base64, mimeType, filename } = input.resource;
138
- const blobRef = await blobService.store(base64, {
137
+ const { data, mimeType, filename } = input.resource;
138
+ const blobRef = await blobService.store(data, {
139
139
  mimeType,
140
140
  originalName: filename,
141
141
  source: "system"
@@ -10,7 +10,7 @@ export interface CreateCustomPromptInput {
10
10
  content: string;
11
11
  arguments?: PromptArgument[];
12
12
  resource?: {
13
- base64: string;
13
+ data: string;
14
14
  mimeType: string;
15
15
  filename?: string;
16
16
  };