@nogataka/smart-edit 0.0.14
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/LICENSE +22 -0
- package/README.md +244 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +7 -0
- package/dist/devtools/generate_prompt_factory.d.ts +5 -0
- package/dist/devtools/generate_prompt_factory.js +114 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +34 -0
- package/dist/interprompt/index.d.ts +2 -0
- package/dist/interprompt/index.js +1 -0
- package/dist/interprompt/jinja_template.d.ts +10 -0
- package/dist/interprompt/jinja_template.js +174 -0
- package/dist/interprompt/multilang_prompt.d.ts +54 -0
- package/dist/interprompt/multilang_prompt.js +302 -0
- package/dist/interprompt/prompt_factory.d.ts +16 -0
- package/dist/interprompt/prompt_factory.js +189 -0
- package/dist/interprompt/util/class_decorators.d.ts +1 -0
- package/dist/interprompt/util/class_decorators.js +1 -0
- package/dist/interprompt/util/index.d.ts +1 -0
- package/dist/interprompt/util/index.js +1 -0
- package/dist/serena/agent.d.ts +118 -0
- package/dist/serena/agent.js +675 -0
- package/dist/serena/agno.d.ts +111 -0
- package/dist/serena/agno.js +278 -0
- package/dist/serena/analytics.d.ts +24 -0
- package/dist/serena/analytics.js +119 -0
- package/dist/serena/cli.d.ts +9 -0
- package/dist/serena/cli.js +731 -0
- package/dist/serena/code_editor.d.ts +42 -0
- package/dist/serena/code_editor.js +239 -0
- package/dist/serena/config/context_mode.d.ts +41 -0
- package/dist/serena/config/context_mode.js +239 -0
- package/dist/serena/config/serena_config.d.ts +134 -0
- package/dist/serena/config/serena_config.js +718 -0
- package/dist/serena/constants.d.ts +18 -0
- package/dist/serena/constants.js +27 -0
- package/dist/serena/dashboard.d.ts +55 -0
- package/dist/serena/dashboard.js +472 -0
- package/dist/serena/generated/generated_prompt_factory.d.ts +27 -0
- package/dist/serena/generated/generated_prompt_factory.js +42 -0
- package/dist/serena/gui_log_viewer.d.ts +41 -0
- package/dist/serena/gui_log_viewer.js +436 -0
- package/dist/serena/mcp.d.ts +118 -0
- package/dist/serena/mcp.js +904 -0
- package/dist/serena/project.d.ts +62 -0
- package/dist/serena/project.js +321 -0
- package/dist/serena/prompt_factory.d.ts +20 -0
- package/dist/serena/prompt_factory.js +42 -0
- package/dist/serena/resources/config/contexts/agent.yml +8 -0
- package/dist/serena/resources/config/contexts/chatgpt.yml +28 -0
- package/dist/serena/resources/config/contexts/codex.yml +27 -0
- package/dist/serena/resources/config/contexts/context.template.yml +11 -0
- package/dist/serena/resources/config/contexts/desktop-app.yml +17 -0
- package/dist/serena/resources/config/contexts/ide-assistant.yml +26 -0
- package/dist/serena/resources/config/contexts/oaicompat-agent.yml +8 -0
- package/dist/serena/resources/config/internal_modes/jetbrains.yml +15 -0
- package/dist/serena/resources/config/modes/editing.yml +112 -0
- package/dist/serena/resources/config/modes/interactive.yml +11 -0
- package/dist/serena/resources/config/modes/mode.template.yml +7 -0
- package/dist/serena/resources/config/modes/no-onboarding.yml +8 -0
- package/dist/serena/resources/config/modes/onboarding.yml +16 -0
- package/dist/serena/resources/config/modes/one-shot.yml +15 -0
- package/dist/serena/resources/config/modes/planning.yml +15 -0
- package/dist/serena/resources/config/prompt_templates/simple_tool_outputs.yml +75 -0
- package/dist/serena/resources/config/prompt_templates/system_prompt.yml +66 -0
- package/dist/serena/resources/dashboard/dashboard.js +815 -0
- package/dist/serena/resources/dashboard/index.html +314 -0
- package/dist/serena/resources/dashboard/jquery.min.js +3 -0
- package/dist/serena/resources/dashboard/serena-icon-16.png +0 -0
- package/dist/serena/resources/dashboard/serena-icon-32.png +0 -0
- package/dist/serena/resources/dashboard/serena-icon-48.png +0 -0
- package/dist/serena/resources/dashboard/serena-logs-dark-mode.png +0 -0
- package/dist/serena/resources/dashboard/serena-logs.png +0 -0
- package/dist/serena/resources/project.template.yml +67 -0
- package/dist/serena/resources/serena_config.template.yml +85 -0
- package/dist/serena/symbol.d.ts +199 -0
- package/dist/serena/symbol.js +616 -0
- package/dist/serena/text_utils.d.ts +51 -0
- package/dist/serena/text_utils.js +267 -0
- package/dist/serena/tools/cmd_tools.d.ts +31 -0
- package/dist/serena/tools/cmd_tools.js +48 -0
- package/dist/serena/tools/config_tools.d.ts +53 -0
- package/dist/serena/tools/config_tools.js +176 -0
- package/dist/serena/tools/file_tools.d.ts +231 -0
- package/dist/serena/tools/file_tools.js +511 -0
- package/dist/serena/tools/index.d.ts +7 -0
- package/dist/serena/tools/index.js +7 -0
- package/dist/serena/tools/memory_tools.d.ts +60 -0
- package/dist/serena/tools/memory_tools.js +135 -0
- package/dist/serena/tools/symbol_tools.d.ts +165 -0
- package/dist/serena/tools/symbol_tools.js +362 -0
- package/dist/serena/tools/tools_base.d.ts +162 -0
- package/dist/serena/tools/tools_base.js +378 -0
- package/dist/serena/tools/workflow_tools.d.ts +35 -0
- package/dist/serena/tools/workflow_tools.js +161 -0
- package/dist/serena/util/class_decorators.d.ts +7 -0
- package/dist/serena/util/class_decorators.js +37 -0
- package/dist/serena/util/exception.d.ts +8 -0
- package/dist/serena/util/exception.js +53 -0
- package/dist/serena/util/file_system.d.ts +30 -0
- package/dist/serena/util/file_system.js +352 -0
- package/dist/serena/util/general.d.ts +11 -0
- package/dist/serena/util/general.js +42 -0
- package/dist/serena/util/git.d.ts +11 -0
- package/dist/serena/util/git.js +37 -0
- package/dist/serena/util/inspection.d.ts +45 -0
- package/dist/serena/util/inspection.js +221 -0
- package/dist/serena/util/logging.d.ts +46 -0
- package/dist/serena/util/logging.js +205 -0
- package/dist/serena/util/shell.d.ts +21 -0
- package/dist/serena/util/shell.js +95 -0
- package/dist/serena/util/thread.d.ts +23 -0
- package/dist/serena/util/thread.js +88 -0
- package/dist/serena/version.d.ts +1 -0
- package/dist/serena/version.js +23 -0
- package/dist/solidlsp/language_servers/autoload.d.ts +23 -0
- package/dist/solidlsp/language_servers/autoload.js +25 -0
- package/dist/solidlsp/language_servers/bash_language_server.d.ts +10 -0
- package/dist/solidlsp/language_servers/bash_language_server.js +64 -0
- package/dist/solidlsp/language_servers/clangd_language_server.d.ts +13 -0
- package/dist/solidlsp/language_servers/clangd_language_server.js +110 -0
- package/dist/solidlsp/language_servers/clojure_lsp.d.ts +13 -0
- package/dist/solidlsp/language_servers/clojure_lsp.js +137 -0
- package/dist/solidlsp/language_servers/common.d.ts +41 -0
- package/dist/solidlsp/language_servers/common.js +365 -0
- package/dist/solidlsp/language_servers/csharp_language_server.d.ts +21 -0
- package/dist/solidlsp/language_servers/csharp_language_server.js +694 -0
- package/dist/solidlsp/language_servers/dart_language_server.d.ts +10 -0
- package/dist/solidlsp/language_servers/dart_language_server.js +122 -0
- package/dist/solidlsp/language_servers/eclipse_jdtls.d.ts +24 -0
- package/dist/solidlsp/language_servers/eclipse_jdtls.js +671 -0
- package/dist/solidlsp/language_servers/erlang_language_server.d.ts +22 -0
- package/dist/solidlsp/language_servers/erlang_language_server.js +327 -0
- package/dist/solidlsp/language_servers/gopls.d.ts +12 -0
- package/dist/solidlsp/language_servers/gopls.js +59 -0
- package/dist/solidlsp/language_servers/intelephense.d.ts +13 -0
- package/dist/solidlsp/language_servers/intelephense.js +121 -0
- package/dist/solidlsp/language_servers/jedi_server.d.ts +18 -0
- package/dist/solidlsp/language_servers/jedi_server.js +234 -0
- package/dist/solidlsp/language_servers/kotlin_language_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/kotlin_language_server.js +474 -0
- package/dist/solidlsp/language_servers/lua_ls.d.ts +18 -0
- package/dist/solidlsp/language_servers/lua_ls.js +319 -0
- package/dist/solidlsp/language_servers/nixd_language_server.d.ts +17 -0
- package/dist/solidlsp/language_servers/nixd_language_server.js +341 -0
- package/dist/solidlsp/language_servers/pyright_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/pyright_server.js +180 -0
- package/dist/solidlsp/language_servers/r_language_server.d.ts +19 -0
- package/dist/solidlsp/language_servers/r_language_server.js +184 -0
- package/dist/solidlsp/language_servers/ruby_common.d.ts +10 -0
- package/dist/solidlsp/language_servers/ruby_common.js +136 -0
- package/dist/solidlsp/language_servers/ruby_lsp.d.ts +18 -0
- package/dist/solidlsp/language_servers/ruby_lsp.js +230 -0
- package/dist/solidlsp/language_servers/rust_analyzer.d.ts +13 -0
- package/dist/solidlsp/language_servers/rust_analyzer.js +96 -0
- package/dist/solidlsp/language_servers/solargraph.d.ts +18 -0
- package/dist/solidlsp/language_servers/solargraph.js +208 -0
- package/dist/solidlsp/language_servers/sourcekit_lsp.d.ts +24 -0
- package/dist/solidlsp/language_servers/sourcekit_lsp.js +449 -0
- package/dist/solidlsp/language_servers/terraform_ls.d.ts +13 -0
- package/dist/solidlsp/language_servers/terraform_ls.js +139 -0
- package/dist/solidlsp/language_servers/typescript_language_server.d.ts +20 -0
- package/dist/solidlsp/language_servers/typescript_language_server.js +237 -0
- package/dist/solidlsp/language_servers/vts_language_server.d.ts +13 -0
- package/dist/solidlsp/language_servers/vts_language_server.js +121 -0
- package/dist/solidlsp/language_servers/zls.d.ts +20 -0
- package/dist/solidlsp/language_servers/zls.js +254 -0
- package/dist/solidlsp/ls.d.ts +197 -0
- package/dist/solidlsp/ls.js +507 -0
- package/dist/solidlsp/ls_config.d.ts +43 -0
- package/dist/solidlsp/ls_config.js +157 -0
- package/dist/solidlsp/ls_exceptions.d.ts +5 -0
- package/dist/solidlsp/ls_exceptions.js +14 -0
- package/dist/solidlsp/ls_handler.d.ts +54 -0
- package/dist/solidlsp/ls_handler.js +406 -0
- package/dist/solidlsp/ls_request.d.ts +31 -0
- package/dist/solidlsp/ls_request.js +42 -0
- package/dist/solidlsp/ls_types.d.ts +7 -0
- package/dist/solidlsp/ls_types.js +8 -0
- package/dist/solidlsp/lsp_protocol_handler/server.d.ts +61 -0
- package/dist/solidlsp/lsp_protocol_handler/server.js +68 -0
- package/dist/solidlsp/util/subprocess_util.d.ts +6 -0
- package/dist/solidlsp/util/subprocess_util.js +11 -0
- package/dist/solidlsp/util/zip.d.ts +25 -0
- package/dist/solidlsp/util/zip.js +188 -0
- package/package.json +65 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type ParameterizedTemplateInterface } from './jinja_template.js';
|
|
2
|
+
export declare const DEFAULT_LANG_CODE = "default";
|
|
3
|
+
export declare enum LanguageFallbackMode {
|
|
4
|
+
ANY = "any",
|
|
5
|
+
EXCEPTION = "exception",
|
|
6
|
+
USE_DEFAULT_LANG = "use_default_lang"
|
|
7
|
+
}
|
|
8
|
+
export declare class PromptTemplate implements ParameterizedTemplateInterface {
|
|
9
|
+
readonly name: string;
|
|
10
|
+
private readonly template;
|
|
11
|
+
constructor(name: string, templateString: string);
|
|
12
|
+
render(params: Record<string, unknown>): string;
|
|
13
|
+
getParameters(): string[];
|
|
14
|
+
}
|
|
15
|
+
export declare class PromptList {
|
|
16
|
+
readonly items: string[];
|
|
17
|
+
constructor(items: string[]);
|
|
18
|
+
toString(): string;
|
|
19
|
+
}
|
|
20
|
+
export declare class MultiLangPromptTemplate implements ParameterizedTemplateInterface {
|
|
21
|
+
private readonly container;
|
|
22
|
+
constructor(name: string);
|
|
23
|
+
get name(): string;
|
|
24
|
+
get length(): number;
|
|
25
|
+
addPromptTemplate(template: PromptTemplate, langCode: string, allowOverwrite: boolean): void;
|
|
26
|
+
hasItem(langCode: string): boolean;
|
|
27
|
+
getPromptTemplate(langCode: string, fallbackMode: LanguageFallbackMode): PromptTemplate;
|
|
28
|
+
getParameters(): string[];
|
|
29
|
+
}
|
|
30
|
+
export declare class MultiLangPromptList {
|
|
31
|
+
private readonly container;
|
|
32
|
+
constructor(name: string);
|
|
33
|
+
addPromptList(list: PromptList, langCode: string, allowOverwrite: boolean): void;
|
|
34
|
+
hasItem(langCode: string): boolean;
|
|
35
|
+
getPromptList(langCode: string, fallbackMode: LanguageFallbackMode): PromptList;
|
|
36
|
+
}
|
|
37
|
+
export declare class MultiLangPromptCollection {
|
|
38
|
+
private readonly promptTemplates;
|
|
39
|
+
private readonly promptLists;
|
|
40
|
+
private _fallbackMode;
|
|
41
|
+
constructor(promptsDir: string | string[], fallbackMode?: LanguageFallbackMode);
|
|
42
|
+
get fallbackMode(): LanguageFallbackMode;
|
|
43
|
+
set fallbackMode(mode: LanguageFallbackMode);
|
|
44
|
+
private loadFromDisk;
|
|
45
|
+
private addPromptTemplate;
|
|
46
|
+
private addPromptList;
|
|
47
|
+
getPromptTemplateNames(): string[];
|
|
48
|
+
getPromptListNames(): string[];
|
|
49
|
+
getPromptTemplate(name: string, langCode: string): PromptTemplate;
|
|
50
|
+
getPromptTemplateParameters(name: string): string[];
|
|
51
|
+
getPromptList(name: string, langCode: string): PromptList;
|
|
52
|
+
hasPromptTemplate(name: string, langCode: string): boolean;
|
|
53
|
+
renderPromptTemplate(name: string, params: Record<string, unknown>, langCode: string): string;
|
|
54
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import yaml from 'yaml';
|
|
4
|
+
import { createSerenaLogger } from '../serena/util/logging.js';
|
|
5
|
+
import { JinjaTemplate } from './jinja_template.js';
|
|
6
|
+
const { logger: log } = createSerenaLogger({ name: 'interprompt.multilang_prompt' });
|
|
7
|
+
export const DEFAULT_LANG_CODE = 'default';
|
|
8
|
+
export var LanguageFallbackMode;
|
|
9
|
+
(function (LanguageFallbackMode) {
|
|
10
|
+
LanguageFallbackMode["ANY"] = "any";
|
|
11
|
+
LanguageFallbackMode["EXCEPTION"] = "exception";
|
|
12
|
+
LanguageFallbackMode["USE_DEFAULT_LANG"] = "use_default_lang";
|
|
13
|
+
})(LanguageFallbackMode || (LanguageFallbackMode = {}));
|
|
14
|
+
export class PromptTemplate {
|
|
15
|
+
name;
|
|
16
|
+
template;
|
|
17
|
+
constructor(name, templateString) {
|
|
18
|
+
this.name = name;
|
|
19
|
+
this.template = new JinjaTemplate(templateString);
|
|
20
|
+
}
|
|
21
|
+
render(params) {
|
|
22
|
+
return this.template.render(params);
|
|
23
|
+
}
|
|
24
|
+
getParameters() {
|
|
25
|
+
return this.template.getParameters();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class PromptList {
|
|
29
|
+
items;
|
|
30
|
+
constructor(items) {
|
|
31
|
+
this.items = items.map((item) => item.trim());
|
|
32
|
+
}
|
|
33
|
+
toString() {
|
|
34
|
+
const bullet = ' * ';
|
|
35
|
+
const indent = ' '.repeat(bullet.length);
|
|
36
|
+
return this.items
|
|
37
|
+
.map((item) => item.replace(/\n/g, `\n${indent}`))
|
|
38
|
+
.map((item, index) => (index === 0 ? `${bullet}${item}` : `${bullet}${item}`))
|
|
39
|
+
.join('\n');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
class MultiLangContainer {
|
|
43
|
+
name;
|
|
44
|
+
lang2item = new Map();
|
|
45
|
+
constructor(name) {
|
|
46
|
+
this.name = name;
|
|
47
|
+
}
|
|
48
|
+
get languageCodes() {
|
|
49
|
+
return Array.from(this.lang2item.keys());
|
|
50
|
+
}
|
|
51
|
+
addItem(item, langCode, allowOverwrite) {
|
|
52
|
+
if (!allowOverwrite && this.lang2item.has(langCode)) {
|
|
53
|
+
throw new Error(`Item for language '${langCode}' already registered for '${this.name}'`);
|
|
54
|
+
}
|
|
55
|
+
this.lang2item.set(langCode, item);
|
|
56
|
+
}
|
|
57
|
+
hasItem(langCode) {
|
|
58
|
+
return this.lang2item.has(langCode);
|
|
59
|
+
}
|
|
60
|
+
getItem(langCode, fallbackMode) {
|
|
61
|
+
const existing = this.lang2item.get(langCode);
|
|
62
|
+
if (existing) {
|
|
63
|
+
return existing;
|
|
64
|
+
}
|
|
65
|
+
if (fallbackMode === LanguageFallbackMode.ANY) {
|
|
66
|
+
const iterator = this.lang2item.values().next();
|
|
67
|
+
if (iterator.done || iterator.value === undefined) {
|
|
68
|
+
throw new Error(`No items registered for any language in container '${this.name}'`);
|
|
69
|
+
}
|
|
70
|
+
return iterator.value;
|
|
71
|
+
}
|
|
72
|
+
if (fallbackMode === LanguageFallbackMode.USE_DEFAULT_LANG) {
|
|
73
|
+
const fallback = this.lang2item.get(DEFAULT_LANG_CODE);
|
|
74
|
+
if (fallback) {
|
|
75
|
+
return fallback;
|
|
76
|
+
}
|
|
77
|
+
throw new Error(`Item not found for language '${langCode}' nor for default language '${DEFAULT_LANG_CODE}' in container '${this.name}'`);
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`Item for language '${langCode}' not found in container '${this.name}'`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
export class MultiLangPromptTemplate {
|
|
83
|
+
container;
|
|
84
|
+
constructor(name) {
|
|
85
|
+
this.container = new MultiLangContainer(name);
|
|
86
|
+
}
|
|
87
|
+
get name() {
|
|
88
|
+
return this.container.name;
|
|
89
|
+
}
|
|
90
|
+
get length() {
|
|
91
|
+
return this.container.languageCodes.length;
|
|
92
|
+
}
|
|
93
|
+
addPromptTemplate(template, langCode, allowOverwrite) {
|
|
94
|
+
if (this.length > 0) {
|
|
95
|
+
const currentParameters = this.getParameters();
|
|
96
|
+
const newParameters = template.getParameters();
|
|
97
|
+
if (JSON.stringify(currentParameters) !== JSON.stringify(newParameters)) {
|
|
98
|
+
throw new Error(`Cannot add prompt template for language '${langCode}' to '${this.name}' because parameters differ`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
this.container.addItem(template, langCode, allowOverwrite);
|
|
102
|
+
}
|
|
103
|
+
hasItem(langCode) {
|
|
104
|
+
return this.container.hasItem(langCode);
|
|
105
|
+
}
|
|
106
|
+
getPromptTemplate(langCode, fallbackMode) {
|
|
107
|
+
return this.container.getItem(langCode, fallbackMode);
|
|
108
|
+
}
|
|
109
|
+
getParameters() {
|
|
110
|
+
if (this.length === 0) {
|
|
111
|
+
throw new Error(`No prompt templates registered for '${this.name}'`);
|
|
112
|
+
}
|
|
113
|
+
const [firstLanguage] = this.container.languageCodes;
|
|
114
|
+
if (!firstLanguage) {
|
|
115
|
+
throw new Error(`No languages registered for '${this.name}'`);
|
|
116
|
+
}
|
|
117
|
+
return this.container.getItem(firstLanguage, LanguageFallbackMode.EXCEPTION).getParameters();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
export class MultiLangPromptList {
|
|
121
|
+
container;
|
|
122
|
+
constructor(name) {
|
|
123
|
+
this.container = new MultiLangContainer(name);
|
|
124
|
+
}
|
|
125
|
+
addPromptList(list, langCode, allowOverwrite) {
|
|
126
|
+
this.container.addItem(list, langCode, allowOverwrite);
|
|
127
|
+
}
|
|
128
|
+
hasItem(langCode) {
|
|
129
|
+
return this.container.hasItem(langCode);
|
|
130
|
+
}
|
|
131
|
+
getPromptList(langCode, fallbackMode) {
|
|
132
|
+
return this.container.getItem(langCode, fallbackMode);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function isPlainObject(value) {
|
|
136
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
137
|
+
}
|
|
138
|
+
function resolveLangCode(...candidates) {
|
|
139
|
+
for (const candidate of candidates) {
|
|
140
|
+
if (isPlainObject(candidate)) {
|
|
141
|
+
const lang = candidate.lang;
|
|
142
|
+
if (typeof lang === 'string' && lang.length > 0) {
|
|
143
|
+
return lang;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return DEFAULT_LANG_CODE;
|
|
148
|
+
}
|
|
149
|
+
function preparePromptEntries(data) {
|
|
150
|
+
if (!isPlainObject(data)) {
|
|
151
|
+
return [];
|
|
152
|
+
}
|
|
153
|
+
const record = data;
|
|
154
|
+
const result = [];
|
|
155
|
+
for (const key of Object.keys(record)) {
|
|
156
|
+
if (key === 'lang') {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
result.push([key, record[key]]);
|
|
160
|
+
}
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
function isStringArray(values) {
|
|
164
|
+
return values.every((value) => typeof value === 'string');
|
|
165
|
+
}
|
|
166
|
+
export class MultiLangPromptCollection {
|
|
167
|
+
promptTemplates = new Map();
|
|
168
|
+
promptLists = new Map();
|
|
169
|
+
_fallbackMode;
|
|
170
|
+
constructor(promptsDir, fallbackMode = LanguageFallbackMode.EXCEPTION) {
|
|
171
|
+
const directories = Array.isArray(promptsDir) ? promptsDir : [promptsDir];
|
|
172
|
+
if (directories.length === 0) {
|
|
173
|
+
throw new Error('At least one prompts directory must be provided');
|
|
174
|
+
}
|
|
175
|
+
const [primary, ...fallbacks] = directories;
|
|
176
|
+
this.loadFromDisk(primary, { onNameCollision: 'raise' });
|
|
177
|
+
for (const fallback of fallbacks) {
|
|
178
|
+
this.loadFromDisk(fallback, { onNameCollision: 'skip' });
|
|
179
|
+
}
|
|
180
|
+
this._fallbackMode = fallbackMode;
|
|
181
|
+
}
|
|
182
|
+
get fallbackMode() {
|
|
183
|
+
return this._fallbackMode;
|
|
184
|
+
}
|
|
185
|
+
set fallbackMode(mode) {
|
|
186
|
+
this._fallbackMode = mode;
|
|
187
|
+
}
|
|
188
|
+
loadFromDisk(directory, options) {
|
|
189
|
+
const entries = fs.readdirSync(directory, { withFileTypes: true });
|
|
190
|
+
for (const entry of entries) {
|
|
191
|
+
if (!entry.isFile()) {
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
194
|
+
if (!entry.name.endsWith('.yml') && !entry.name.endsWith('.yaml')) {
|
|
195
|
+
log.debug(`Skipping non-YAML file: ${entry.name}`);
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
const absolutePath = path.join(directory, entry.name);
|
|
199
|
+
const fileContents = fs.readFileSync(absolutePath, 'utf-8');
|
|
200
|
+
let parsed;
|
|
201
|
+
try {
|
|
202
|
+
parsed = yaml.parse(fileContents);
|
|
203
|
+
}
|
|
204
|
+
catch (error) {
|
|
205
|
+
throw new Error(`Failed to parse prompt yaml file ${absolutePath}: ${error.message}`);
|
|
206
|
+
}
|
|
207
|
+
if (typeof parsed !== 'object' || parsed === null || !('prompts' in parsed)) {
|
|
208
|
+
throw new Error(`Invalid YAML structure in ${absolutePath}; missing 'prompts' key`);
|
|
209
|
+
}
|
|
210
|
+
const promptsSection = parsed.prompts;
|
|
211
|
+
const langCode = resolveLangCode(parsed, promptsSection);
|
|
212
|
+
const promptEntries = preparePromptEntries(promptsSection);
|
|
213
|
+
for (const [promptName, promptValue] of promptEntries) {
|
|
214
|
+
if (Array.isArray(promptValue)) {
|
|
215
|
+
if (isStringArray(promptValue)) {
|
|
216
|
+
this.addPromptList(promptName, [...promptValue], langCode, options.onNameCollision);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
throw new Error(`Prompt list '${promptName}' in ${absolutePath} must contain only strings`);
|
|
220
|
+
}
|
|
221
|
+
else if (typeof promptValue === 'string') {
|
|
222
|
+
this.addPromptTemplate(promptName, promptValue, langCode, options.onNameCollision);
|
|
223
|
+
}
|
|
224
|
+
else {
|
|
225
|
+
throw new Error(`Invalid prompt entry '${promptName}' in ${absolutePath}; expected string or list, received ${typeof promptValue}`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
addPromptTemplate(name, templateString, langCode, onNameCollision) {
|
|
231
|
+
const promptTemplate = new PromptTemplate(name, templateString);
|
|
232
|
+
let container = this.promptTemplates.get(name);
|
|
233
|
+
if (!container) {
|
|
234
|
+
container = new MultiLangPromptTemplate(name);
|
|
235
|
+
this.promptTemplates.set(name, container);
|
|
236
|
+
}
|
|
237
|
+
const allowOverwrite = onNameCollision === 'overwrite';
|
|
238
|
+
if (container.hasItem(langCode)) {
|
|
239
|
+
if (onNameCollision === 'skip') {
|
|
240
|
+
log.debug(`Skipping prompt '${name}' for language '${langCode}' because it already exists`);
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (onNameCollision === 'raise') {
|
|
244
|
+
throw new Error(`Prompt '${name}' for language '${langCode}' already exists`);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
container.addPromptTemplate(promptTemplate, langCode, allowOverwrite);
|
|
248
|
+
}
|
|
249
|
+
addPromptList(name, promptValues, langCode, onNameCollision) {
|
|
250
|
+
const promptList = new PromptList(promptValues);
|
|
251
|
+
let container = this.promptLists.get(name);
|
|
252
|
+
if (!container) {
|
|
253
|
+
container = new MultiLangPromptList(name);
|
|
254
|
+
this.promptLists.set(name, container);
|
|
255
|
+
}
|
|
256
|
+
const allowOverwrite = onNameCollision === 'overwrite';
|
|
257
|
+
if (container.hasItem(langCode)) {
|
|
258
|
+
if (onNameCollision === 'skip') {
|
|
259
|
+
log.debug(`Skipping prompt list '${name}' for language '${langCode}' because it already exists`);
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (onNameCollision === 'raise') {
|
|
263
|
+
throw new Error(`Prompt list '${name}' for language '${langCode}' already exists`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
container.addPromptList(promptList, langCode, allowOverwrite);
|
|
267
|
+
}
|
|
268
|
+
getPromptTemplateNames() {
|
|
269
|
+
return Array.from(this.promptTemplates.keys());
|
|
270
|
+
}
|
|
271
|
+
getPromptListNames() {
|
|
272
|
+
return Array.from(this.promptLists.keys());
|
|
273
|
+
}
|
|
274
|
+
getPromptTemplate(name, langCode) {
|
|
275
|
+
const container = this.promptTemplates.get(name);
|
|
276
|
+
if (!container) {
|
|
277
|
+
throw new Error(`Prompt template '${name}' not found`);
|
|
278
|
+
}
|
|
279
|
+
return container.getPromptTemplate(langCode, this._fallbackMode);
|
|
280
|
+
}
|
|
281
|
+
getPromptTemplateParameters(name) {
|
|
282
|
+
const container = this.promptTemplates.get(name);
|
|
283
|
+
if (!container) {
|
|
284
|
+
throw new Error(`Prompt template '${name}' not found`);
|
|
285
|
+
}
|
|
286
|
+
return container.getParameters();
|
|
287
|
+
}
|
|
288
|
+
getPromptList(name, langCode) {
|
|
289
|
+
const container = this.promptLists.get(name);
|
|
290
|
+
if (!container) {
|
|
291
|
+
throw new Error(`Prompt list '${name}' not found`);
|
|
292
|
+
}
|
|
293
|
+
return container.getPromptList(langCode, this._fallbackMode);
|
|
294
|
+
}
|
|
295
|
+
hasPromptTemplate(name, langCode) {
|
|
296
|
+
return this.promptTemplates.get(name)?.hasItem(langCode) ?? false;
|
|
297
|
+
}
|
|
298
|
+
renderPromptTemplate(name, params, langCode) {
|
|
299
|
+
const template = this.getPromptTemplate(name, langCode);
|
|
300
|
+
return template.render(params);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MultiLangPromptCollection, type PromptList } from './multilang_prompt.js';
|
|
2
|
+
import type { LanguageFallbackMode } from './multilang_prompt.js';
|
|
3
|
+
export interface PromptFactoryBaseOptions {
|
|
4
|
+
promptsDir: string | string[];
|
|
5
|
+
langCode?: string;
|
|
6
|
+
fallbackMode?: LanguageFallbackMode;
|
|
7
|
+
}
|
|
8
|
+
export declare class PromptFactoryBase {
|
|
9
|
+
protected readonly langCode: string;
|
|
10
|
+
protected readonly promptCollection: MultiLangPromptCollection;
|
|
11
|
+
constructor(options: PromptFactoryBaseOptions);
|
|
12
|
+
protected renderPromptTemplate(promptName: string, params: Record<string, unknown>): string;
|
|
13
|
+
protected getPromptList(promptName: string): PromptList;
|
|
14
|
+
}
|
|
15
|
+
export { PromptList, DEFAULT_LANG_CODE, LanguageFallbackMode } from './multilang_prompt.js';
|
|
16
|
+
export declare function autogeneratePromptFactoryModule(promptsDir: string | string[], targetModulePath: string): void;
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { createSerenaLogger } from '../serena/util/logging.js';
|
|
5
|
+
import { MultiLangPromptCollection, DEFAULT_LANG_CODE } from './multilang_prompt.js';
|
|
6
|
+
export class PromptFactoryBase {
|
|
7
|
+
langCode;
|
|
8
|
+
promptCollection;
|
|
9
|
+
constructor(options) {
|
|
10
|
+
this.langCode = options.langCode ?? DEFAULT_LANG_CODE;
|
|
11
|
+
this.promptCollection = new MultiLangPromptCollection(options.promptsDir, options.fallbackMode);
|
|
12
|
+
}
|
|
13
|
+
renderPromptTemplate(promptName, params) {
|
|
14
|
+
const safeParams = { ...params };
|
|
15
|
+
delete safeParams.self;
|
|
16
|
+
return this.promptCollection.renderPromptTemplate(promptName, safeParams, this.langCode);
|
|
17
|
+
}
|
|
18
|
+
getPromptList(promptName) {
|
|
19
|
+
return this.promptCollection.getPromptList(promptName, this.langCode);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export { PromptList, DEFAULT_LANG_CODE, LanguageFallbackMode } from './multilang_prompt.js';
|
|
23
|
+
const MODULE_PATH = fileURLToPath(import.meta.url);
|
|
24
|
+
const MODULE_JS_PATH = MODULE_PATH.replace(/\.ts$/, '.js');
|
|
25
|
+
const { logger: promptFactoryLogger } = createSerenaLogger({ name: 'interprompt.prompt_factory' });
|
|
26
|
+
function toPascalCase(value) {
|
|
27
|
+
return value
|
|
28
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
29
|
+
.filter((segment) => segment.length > 0)
|
|
30
|
+
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
31
|
+
.join('');
|
|
32
|
+
}
|
|
33
|
+
function toCamelCase(value) {
|
|
34
|
+
const pascal = toPascalCase(value);
|
|
35
|
+
if (pascal.length === 0) {
|
|
36
|
+
return pascal;
|
|
37
|
+
}
|
|
38
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
39
|
+
}
|
|
40
|
+
function toPosixPath(value) {
|
|
41
|
+
return value.replace(/\\/g, '/');
|
|
42
|
+
}
|
|
43
|
+
function inferParamSpec(templateName, paramName) {
|
|
44
|
+
const snake = paramName;
|
|
45
|
+
const camel = toCamelCase(paramName);
|
|
46
|
+
const lower = paramName.toLowerCase();
|
|
47
|
+
let type = 'unknown';
|
|
48
|
+
let optional = false;
|
|
49
|
+
let needsArrayConversion = false;
|
|
50
|
+
if (lower === 'system') {
|
|
51
|
+
type = 'string';
|
|
52
|
+
}
|
|
53
|
+
else if (lower.endsWith('_prompt')) {
|
|
54
|
+
type = 'string';
|
|
55
|
+
}
|
|
56
|
+
else if (lower.endsWith('_prompts') || lower.endsWith('_tools') || lower.endsWith('_markers')) {
|
|
57
|
+
type = 'Iterable<string>';
|
|
58
|
+
needsArrayConversion = true;
|
|
59
|
+
}
|
|
60
|
+
else if (lower.endsWith('_dir') || lower.endsWith('_path')) {
|
|
61
|
+
type = 'string';
|
|
62
|
+
}
|
|
63
|
+
if (templateName === 'prepare_for_new_conversation' && lower === 'mode_prepare_for_new_conversation') {
|
|
64
|
+
type = 'string | undefined';
|
|
65
|
+
optional = true;
|
|
66
|
+
}
|
|
67
|
+
return { snake, camel, type, optional, needsArrayConversion };
|
|
68
|
+
}
|
|
69
|
+
function normalizeImportPath(from, to) {
|
|
70
|
+
const relative = path.relative(from, to);
|
|
71
|
+
const normalized = toPosixPath(relative.startsWith('.') ? relative : `./${relative}`);
|
|
72
|
+
return normalized.endsWith('.js') ? normalized : `${normalized}.js`;
|
|
73
|
+
}
|
|
74
|
+
export function autogeneratePromptFactoryModule(promptsDir, targetModulePath) {
|
|
75
|
+
const collection = new MultiLangPromptCollection(promptsDir);
|
|
76
|
+
const dir = path.dirname(targetModulePath);
|
|
77
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
78
|
+
const templateNames = [...collection.getPromptTemplateNames()].sort();
|
|
79
|
+
const promptListNames = [...collection.getPromptListNames()].sort();
|
|
80
|
+
const templateSpecs = templateNames.map((name) => ({
|
|
81
|
+
name,
|
|
82
|
+
pascal: toPascalCase(name),
|
|
83
|
+
camel: `create${toPascalCase(name)}`,
|
|
84
|
+
snake: `create_${name}`,
|
|
85
|
+
params: collection.getPromptTemplateParameters(name).map((param) => inferParamSpec(name, param))
|
|
86
|
+
}));
|
|
87
|
+
const promptListSpecs = promptListNames.map((name) => ({
|
|
88
|
+
name,
|
|
89
|
+
pascal: toPascalCase(name),
|
|
90
|
+
camel: `getList${toPascalCase(name)}`,
|
|
91
|
+
snake: `get_list_${name}`
|
|
92
|
+
}));
|
|
93
|
+
const importPath = normalizeImportPath(dir, MODULE_JS_PATH);
|
|
94
|
+
const lines = [];
|
|
95
|
+
lines.push('// NOTE: This module is auto-generated via interprompt.autogeneratePromptFactoryModule. Do not edit manually.');
|
|
96
|
+
lines.push('');
|
|
97
|
+
lines.push('import {');
|
|
98
|
+
lines.push(' PromptFactoryBase,');
|
|
99
|
+
lines.push(' type PromptFactoryBaseOptions,');
|
|
100
|
+
if (promptListSpecs.length > 0) {
|
|
101
|
+
lines.push(' type PromptList');
|
|
102
|
+
}
|
|
103
|
+
lines.push(`} from '${importPath}';`);
|
|
104
|
+
lines.push('');
|
|
105
|
+
for (const spec of templateSpecs) {
|
|
106
|
+
if (spec.params.length === 0) {
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const interfaceName = `Create${spec.pascal}Params`;
|
|
110
|
+
lines.push(`export interface ${interfaceName} {`);
|
|
111
|
+
for (const param of spec.params) {
|
|
112
|
+
const optionalMark = param.optional ? '?' : '';
|
|
113
|
+
lines.push(` ${param.camel}${optionalMark}: ${param.type};`);
|
|
114
|
+
}
|
|
115
|
+
lines.push('}');
|
|
116
|
+
lines.push('');
|
|
117
|
+
}
|
|
118
|
+
lines.push('export class PromptFactory extends PromptFactoryBase {');
|
|
119
|
+
for (const spec of templateSpecs) {
|
|
120
|
+
const typeAnnotation = spec.params.length === 0 ? '() => string' : `(params: Create${spec.pascal}Params) => string`;
|
|
121
|
+
lines.push(` declare ${spec.snake}: ${typeAnnotation};`);
|
|
122
|
+
}
|
|
123
|
+
if (promptListSpecs.length > 0) {
|
|
124
|
+
for (const spec of promptListSpecs) {
|
|
125
|
+
lines.push(` declare ${spec.snake}: () => PromptList;`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
if (templateSpecs.length > 0 || promptListSpecs.length > 0) {
|
|
129
|
+
lines.push('');
|
|
130
|
+
}
|
|
131
|
+
lines.push(' constructor(options: PromptFactoryBaseOptions) {');
|
|
132
|
+
lines.push(' super(options);');
|
|
133
|
+
for (const spec of templateSpecs) {
|
|
134
|
+
const callArgs = spec.params.length === 0 ? '' : 'params';
|
|
135
|
+
const arrowParams = spec.params.length === 0 ? '' : 'params';
|
|
136
|
+
const assignment = spec.params.length === 0
|
|
137
|
+
? ` this.${spec.snake} = () => this.${spec.camel}();`
|
|
138
|
+
: ` this.${spec.snake} = (${arrowParams}) => this.${spec.camel}(${callArgs});`;
|
|
139
|
+
lines.push(assignment);
|
|
140
|
+
}
|
|
141
|
+
if (promptListSpecs.length > 0) {
|
|
142
|
+
for (const spec of promptListSpecs) {
|
|
143
|
+
lines.push(` this.${spec.snake} = () => this.${spec.camel}();`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
lines.push(' }');
|
|
147
|
+
lines.push('');
|
|
148
|
+
for (const spec of templateSpecs) {
|
|
149
|
+
const methodSignature = spec.params.length === 0
|
|
150
|
+
? `${spec.camel}(): string`
|
|
151
|
+
: `${spec.camel}(params: Create${spec.pascal}Params): string`;
|
|
152
|
+
lines.push(` ${methodSignature} {`);
|
|
153
|
+
if (spec.params.length === 0) {
|
|
154
|
+
lines.push(` return this.renderPromptTemplate('${spec.name}', {});`);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
lines.push(' return this.renderPromptTemplate(');
|
|
158
|
+
lines.push(` '${spec.name}',`);
|
|
159
|
+
lines.push(' {');
|
|
160
|
+
for (let index = 0; index < spec.params.length; index += 1) {
|
|
161
|
+
const param = spec.params[index];
|
|
162
|
+
const suffix = index === spec.params.length - 1 ? '' : ',';
|
|
163
|
+
if (param.needsArrayConversion) {
|
|
164
|
+
lines.push(` ${param.snake}: Array.from(params.${param.camel} ?? [])${suffix}`);
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
lines.push(` ${param.snake}: params.${param.camel}${suffix}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
lines.push(' }');
|
|
171
|
+
lines.push(' );');
|
|
172
|
+
}
|
|
173
|
+
lines.push(' }');
|
|
174
|
+
lines.push('');
|
|
175
|
+
}
|
|
176
|
+
if (promptListSpecs.length > 0) {
|
|
177
|
+
for (const spec of promptListSpecs) {
|
|
178
|
+
lines.push(` ${spec.camel}(): PromptList {`);
|
|
179
|
+
lines.push(` return this.getPromptList('${spec.name}');`);
|
|
180
|
+
lines.push(' }');
|
|
181
|
+
lines.push('');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
lines.push('}');
|
|
185
|
+
lines.push('');
|
|
186
|
+
const fileContents = `${lines.join('\n').trimEnd()}\n`;
|
|
187
|
+
fs.writeFileSync(targetModulePath, fileContents, 'utf-8');
|
|
188
|
+
promptFactoryLogger.info(`Prompt factory generated successfully at ${targetModulePath}`);
|
|
189
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { singleton } from '../../serena/util/class_decorators.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { singleton } from '../../serena/util/class_decorators.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { singleton } from './class_decorators.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { singleton } from './class_decorators.js';
|