@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,162 @@
|
|
|
1
|
+
import { type ZodTypeAny } from 'zod';
|
|
2
|
+
import type { SerenaAgentMode } from '../config/context_mode.js';
|
|
3
|
+
import type { Language } from '../../solidlsp/ls_config.js';
|
|
4
|
+
import type { SerenaPromptFactory } from '../prompt_factory.js';
|
|
5
|
+
import type { SolidLanguageServer } from '../../solidlsp/ls.js';
|
|
6
|
+
import type { LanguageServerSymbolRetriever } from '../symbol.js';
|
|
7
|
+
import type { LanguageServerCodeEditor } from '../code_editor.js';
|
|
8
|
+
import type { LinesRead } from '../agent.js';
|
|
9
|
+
export declare function assertIsBufferEncoding(value: string): asserts value is BufferEncoding;
|
|
10
|
+
export declare const SUCCESS_RESULT = "OK";
|
|
11
|
+
export declare const ToolMarkerCanEdit: "can-edit";
|
|
12
|
+
export declare const ToolMarkerDoesNotRequireActiveProject: "does-not-require-active-project";
|
|
13
|
+
export declare const ToolMarkerOptional: "optional";
|
|
14
|
+
export declare const ToolMarkerSymbolicRead: "symbolic-read";
|
|
15
|
+
export declare const ToolMarkerSymbolicEdit: "symbolic-edit";
|
|
16
|
+
export type ToolMarker = typeof ToolMarkerCanEdit | typeof ToolMarkerDoesNotRequireActiveProject | typeof ToolMarkerOptional | typeof ToolMarkerSymbolicRead | typeof ToolMarkerSymbolicEdit;
|
|
17
|
+
export interface SerenaConfigLike {
|
|
18
|
+
defaultMaxToolAnswerChars: number;
|
|
19
|
+
toolTimeout: number;
|
|
20
|
+
projectNames: string[];
|
|
21
|
+
removeProject?(projectName: string): void;
|
|
22
|
+
}
|
|
23
|
+
export interface ProjectConfigLike {
|
|
24
|
+
encoding: string;
|
|
25
|
+
language?: Language | {
|
|
26
|
+
value: string;
|
|
27
|
+
} | string;
|
|
28
|
+
initialPrompt?: string;
|
|
29
|
+
projectName?: string;
|
|
30
|
+
}
|
|
31
|
+
export interface ProjectLike {
|
|
32
|
+
projectRoot: string;
|
|
33
|
+
projectConfig: ProjectConfigLike;
|
|
34
|
+
isNewlyCreated?: boolean;
|
|
35
|
+
pathToProjectYml?: () => string;
|
|
36
|
+
}
|
|
37
|
+
export type PromptFactoryLike = SerenaPromptFactory;
|
|
38
|
+
export interface MemoriesManagerLike {
|
|
39
|
+
listMemories(): string[] | Promise<string[]> | Iterable<unknown> | Promise<Iterable<unknown>>;
|
|
40
|
+
list_memories?(): string[] | Promise<string[]> | Iterable<unknown> | Promise<Iterable<unknown>>;
|
|
41
|
+
saveMemory?(name: string, content: string): string | Promise<string>;
|
|
42
|
+
save_memory?(name: string, content: string): string | Promise<string>;
|
|
43
|
+
loadMemory?(name: string): string | Promise<string>;
|
|
44
|
+
load_memory?(name: string): string | Promise<string>;
|
|
45
|
+
deleteMemory?(name: string): string | Promise<string>;
|
|
46
|
+
delete_memory?(name: string): string | Promise<string>;
|
|
47
|
+
}
|
|
48
|
+
export type LinesReadLike = LinesRead;
|
|
49
|
+
export type LanguageServerLike = SolidLanguageServer;
|
|
50
|
+
export type CodeEditorLike = LanguageServerCodeEditor;
|
|
51
|
+
export type LanguageServerSymbolRetrieverLike = LanguageServerSymbolRetriever;
|
|
52
|
+
export interface IssueTaskMetadata {
|
|
53
|
+
name?: string;
|
|
54
|
+
}
|
|
55
|
+
export interface AgentTaskHandle<T> {
|
|
56
|
+
result(options?: {
|
|
57
|
+
timeout?: number;
|
|
58
|
+
}): Promise<T>;
|
|
59
|
+
}
|
|
60
|
+
export interface SerenaAgentLike {
|
|
61
|
+
readonly promptFactory: PromptFactoryLike;
|
|
62
|
+
readonly memoriesManager: MemoriesManagerLike | null;
|
|
63
|
+
readonly serenaConfig: SerenaConfigLike;
|
|
64
|
+
readonly languageServer: LanguageServerLike | null;
|
|
65
|
+
readonly linesRead: LinesReadLike | null;
|
|
66
|
+
getProjectRoot(): string;
|
|
67
|
+
getActiveProject(): ProjectLike | null;
|
|
68
|
+
getActiveProjectOrThrow(): ProjectLike;
|
|
69
|
+
getActiveToolNames(): string[];
|
|
70
|
+
toolIsActive(toolClass: ToolClass | string): boolean;
|
|
71
|
+
isUsingLanguageServer(): boolean;
|
|
72
|
+
isLanguageServerRunning(): boolean;
|
|
73
|
+
resetLanguageServer(): void | Promise<void>;
|
|
74
|
+
activateProjectFromPathOrName(project: string): Promise<ProjectLike>;
|
|
75
|
+
setModes(modes: SerenaAgentMode[]): void | Promise<void>;
|
|
76
|
+
getCurrentConfigOverview(): string | Promise<string>;
|
|
77
|
+
createLanguageServerSymbolRetriever(): LanguageServerSymbolRetrieverLike;
|
|
78
|
+
createCodeEditor(): CodeEditorLike;
|
|
79
|
+
recordToolUsageIfEnabled(args: Record<string, unknown>, result: string | Record<string, unknown>, tool: Tool): void | Promise<void>;
|
|
80
|
+
issueTask<T>(task: () => Promise<T> | T, metadata?: IssueTaskMetadata): AgentTaskHandle<T>;
|
|
81
|
+
}
|
|
82
|
+
export type ToolApplyFunction<Input = Record<string, unknown>, Output = string> = (input: Input) => Promise<Output> | Output;
|
|
83
|
+
export interface ToolApplyMetadata {
|
|
84
|
+
inputSchema: ZodTypeAny;
|
|
85
|
+
outputSchema?: ZodTypeAny;
|
|
86
|
+
structuredOutput?: boolean;
|
|
87
|
+
description?: string;
|
|
88
|
+
}
|
|
89
|
+
export interface ToolExecutionOptions {
|
|
90
|
+
logCall?: boolean;
|
|
91
|
+
catchExceptions?: boolean;
|
|
92
|
+
maxAnswerChars?: number;
|
|
93
|
+
}
|
|
94
|
+
export type ToolClass<T extends Tool = Tool> = (new (agent: SerenaAgentLike) => T) & typeof Tool;
|
|
95
|
+
export declare abstract class Component {
|
|
96
|
+
protected readonly agent: SerenaAgentLike;
|
|
97
|
+
constructor(agent: SerenaAgentLike);
|
|
98
|
+
getProjectRoot(): string;
|
|
99
|
+
protected get promptFactory(): PromptFactoryLike;
|
|
100
|
+
protected get memoriesManager(): MemoriesManagerLike;
|
|
101
|
+
protected createLanguageServerSymbolRetriever(): LanguageServerSymbolRetrieverLike;
|
|
102
|
+
protected get project(): ProjectLike;
|
|
103
|
+
protected createCodeEditor(): CodeEditorLike;
|
|
104
|
+
protected get linesRead(): LinesReadLike;
|
|
105
|
+
}
|
|
106
|
+
export declare abstract class Tool extends Component {
|
|
107
|
+
protected static readonly markers: ReadonlySet<ToolMarker>;
|
|
108
|
+
static readonly inputSchema: ZodTypeAny;
|
|
109
|
+
static readonly outputSchema: ZodTypeAny | undefined;
|
|
110
|
+
static readonly structuredOutput: boolean | undefined;
|
|
111
|
+
static readonly description: string | undefined;
|
|
112
|
+
abstract apply(args: unknown): Promise<string>;
|
|
113
|
+
static getNameFromCls(): string;
|
|
114
|
+
getName(): string;
|
|
115
|
+
static hasMarker(marker: ToolMarker): boolean;
|
|
116
|
+
hasMarker(marker: ToolMarker): boolean;
|
|
117
|
+
getApplyFn(): ToolApplyFunction<Record<string, unknown>, string>;
|
|
118
|
+
static canEdit(): boolean;
|
|
119
|
+
static getToolDescription(): string;
|
|
120
|
+
getApplyDocstring(): string;
|
|
121
|
+
static getApplyFnMetadata(): ToolApplyMetadata;
|
|
122
|
+
getApplyFnMetadata(): ToolApplyMetadata;
|
|
123
|
+
protected _limitLength(result: string, maxAnswerChars: number): string;
|
|
124
|
+
isActive(): boolean;
|
|
125
|
+
applyEx(args?: Record<string, unknown>, options?: ToolExecutionOptions): Promise<string>;
|
|
126
|
+
}
|
|
127
|
+
declare class EditedFileContextImpl {
|
|
128
|
+
private readonly project;
|
|
129
|
+
private readonly absolutePath;
|
|
130
|
+
private readonly originalContent;
|
|
131
|
+
private updatedContent;
|
|
132
|
+
constructor(relativePath: string, agent: SerenaAgentLike);
|
|
133
|
+
getOriginalContent(): string;
|
|
134
|
+
setUpdatedContent(content: string): void;
|
|
135
|
+
commit(): Promise<void>;
|
|
136
|
+
}
|
|
137
|
+
export declare class EditedFileContext {
|
|
138
|
+
static use<T>(relativePath: string, agent: SerenaAgentLike, handler: (context: EditedFileContextImpl) => Promise<T> | T): Promise<T>;
|
|
139
|
+
}
|
|
140
|
+
declare class ToolRegistryImpl {
|
|
141
|
+
private readonly toolMap;
|
|
142
|
+
registerToolClass(toolClass: ToolClass): void;
|
|
143
|
+
registerMany(toolClasses: Iterable<ToolClass>): void;
|
|
144
|
+
getToolClassByName(toolName: string): ToolClass;
|
|
145
|
+
getAllToolClasses(): ToolClass[];
|
|
146
|
+
getToolClassesDefaultEnabled(): ToolClass[];
|
|
147
|
+
getToolClassesOptional(): ToolClass[];
|
|
148
|
+
getToolNamesDefaultEnabled(): string[];
|
|
149
|
+
getToolNamesOptional(): string[];
|
|
150
|
+
getToolNames(): string[];
|
|
151
|
+
isValidToolName(toolName: string): boolean;
|
|
152
|
+
printToolOverview(tools?: Iterable<ToolClass | Tool>, options?: {
|
|
153
|
+
includeOptional?: boolean;
|
|
154
|
+
onlyOptional?: boolean;
|
|
155
|
+
}): void;
|
|
156
|
+
/** @internal */
|
|
157
|
+
resetForTesting(): void;
|
|
158
|
+
}
|
|
159
|
+
declare const ToolRegistrySingleton: typeof ToolRegistryImpl;
|
|
160
|
+
export type ToolRegistry = InstanceType<typeof ToolRegistryImpl>;
|
|
161
|
+
export { ToolRegistrySingleton as ToolRegistry };
|
|
162
|
+
export declare function registerToolClass(toolClass: ToolClass): void;
|
|
@@ -0,0 +1,378 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { createSerenaLogger } from '../util/logging.js';
|
|
5
|
+
import { singleton } from '../util/class_decorators.js';
|
|
6
|
+
const { logger: log } = createSerenaLogger({ name: 'serena.tools.base' });
|
|
7
|
+
export function assertIsBufferEncoding(value) {
|
|
8
|
+
if (!Buffer.isEncoding(value)) {
|
|
9
|
+
throw new Error(`Unsupported file encoding '${value}'`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function resolveProjectEncoding(encodingValue) {
|
|
13
|
+
const candidate = encodingValue ?? 'utf-8';
|
|
14
|
+
assertIsBufferEncoding(candidate);
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
17
|
+
export const SUCCESS_RESULT = 'OK';
|
|
18
|
+
export const ToolMarkerCanEdit = 'can-edit';
|
|
19
|
+
export const ToolMarkerDoesNotRequireActiveProject = 'does-not-require-active-project';
|
|
20
|
+
export const ToolMarkerOptional = 'optional';
|
|
21
|
+
export const ToolMarkerSymbolicRead = 'symbolic-read';
|
|
22
|
+
export const ToolMarkerSymbolicEdit = 'symbolic-edit';
|
|
23
|
+
function formatDictionary(value) {
|
|
24
|
+
const parts = Object.entries(value).map(([key, val]) => {
|
|
25
|
+
try {
|
|
26
|
+
return `${key}=${JSON.stringify(val)}`;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return `${key}=${String(val)}`;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
return `{${parts.join(', ')}}`;
|
|
33
|
+
}
|
|
34
|
+
function describeError(error) {
|
|
35
|
+
if (error instanceof Error && typeof error.message === 'string' && error.message.length > 0) {
|
|
36
|
+
return error.message;
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
return JSON.stringify(error);
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return String(error);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function isSolidLspTerminationError(error) {
|
|
46
|
+
if (typeof error !== 'object' || error === null) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (!('isLanguageServerTerminated' in error)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const candidate = error.isLanguageServerTerminated;
|
|
53
|
+
return typeof candidate === 'function';
|
|
54
|
+
}
|
|
55
|
+
export class Component {
|
|
56
|
+
agent;
|
|
57
|
+
constructor(agent) {
|
|
58
|
+
this.agent = agent;
|
|
59
|
+
}
|
|
60
|
+
getProjectRoot() {
|
|
61
|
+
return this.agent.getProjectRoot();
|
|
62
|
+
}
|
|
63
|
+
get promptFactory() {
|
|
64
|
+
return this.agent.promptFactory;
|
|
65
|
+
}
|
|
66
|
+
get memoriesManager() {
|
|
67
|
+
const manager = this.agent.memoriesManager;
|
|
68
|
+
if (!manager) {
|
|
69
|
+
throw new Error('Memories manager is not initialized.');
|
|
70
|
+
}
|
|
71
|
+
return manager;
|
|
72
|
+
}
|
|
73
|
+
createLanguageServerSymbolRetriever() {
|
|
74
|
+
if (!this.agent.isUsingLanguageServer()) {
|
|
75
|
+
throw new Error('Cannot create LanguageServerSymbolRetriever; agent is not in language server mode.');
|
|
76
|
+
}
|
|
77
|
+
return this.agent.createLanguageServerSymbolRetriever();
|
|
78
|
+
}
|
|
79
|
+
get project() {
|
|
80
|
+
return this.agent.getActiveProjectOrThrow();
|
|
81
|
+
}
|
|
82
|
+
createCodeEditor() {
|
|
83
|
+
return this.agent.createCodeEditor();
|
|
84
|
+
}
|
|
85
|
+
get linesRead() {
|
|
86
|
+
const value = this.agent.linesRead;
|
|
87
|
+
if (!value) {
|
|
88
|
+
throw new Error('linesRead not initialized on agent.');
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
export class Tool extends Component {
|
|
94
|
+
static markers = new Set();
|
|
95
|
+
static inputSchema = z.object({}).passthrough();
|
|
96
|
+
static outputSchema;
|
|
97
|
+
static structuredOutput;
|
|
98
|
+
static description;
|
|
99
|
+
static getNameFromCls() {
|
|
100
|
+
const name = this.name.endsWith('Tool') ? this.name.slice(0, -4) : this.name;
|
|
101
|
+
const snake = name
|
|
102
|
+
.replace(/([A-Z]+)/g, '_$1')
|
|
103
|
+
.replace(/^_/, '')
|
|
104
|
+
.toLowerCase();
|
|
105
|
+
return snake;
|
|
106
|
+
}
|
|
107
|
+
getName() {
|
|
108
|
+
return this.constructor.getNameFromCls();
|
|
109
|
+
}
|
|
110
|
+
static hasMarker(marker) {
|
|
111
|
+
return this.markers.has(marker);
|
|
112
|
+
}
|
|
113
|
+
hasMarker(marker) {
|
|
114
|
+
return this.constructor.hasMarker(marker);
|
|
115
|
+
}
|
|
116
|
+
getApplyFn() {
|
|
117
|
+
const applyFn = this.apply;
|
|
118
|
+
if (!applyFn) {
|
|
119
|
+
throw new Error(`apply not defined in ${this.constructor.name}. Did you forget to implement it?`);
|
|
120
|
+
}
|
|
121
|
+
return applyFn.bind(this);
|
|
122
|
+
}
|
|
123
|
+
static canEdit() {
|
|
124
|
+
return this.hasMarker(ToolMarkerCanEdit) || this.hasMarker(ToolMarkerSymbolicEdit);
|
|
125
|
+
}
|
|
126
|
+
static getToolDescription() {
|
|
127
|
+
return (this.description ?? '').trim();
|
|
128
|
+
}
|
|
129
|
+
getApplyDocstring() {
|
|
130
|
+
const metadata = this.getApplyFnMetadata();
|
|
131
|
+
return metadata.description ?? '';
|
|
132
|
+
}
|
|
133
|
+
static getApplyFnMetadata() {
|
|
134
|
+
return {
|
|
135
|
+
inputSchema: this.inputSchema,
|
|
136
|
+
outputSchema: this.outputSchema,
|
|
137
|
+
structuredOutput: this.structuredOutput,
|
|
138
|
+
description: this.getToolDescription()
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
getApplyFnMetadata() {
|
|
142
|
+
return this.constructor.getApplyFnMetadata();
|
|
143
|
+
}
|
|
144
|
+
_limitLength(result, maxAnswerChars) {
|
|
145
|
+
let limit = maxAnswerChars;
|
|
146
|
+
if (limit === -1 || limit === undefined || limit === null) {
|
|
147
|
+
limit = this.agent.serenaConfig.defaultMaxToolAnswerChars;
|
|
148
|
+
}
|
|
149
|
+
if (limit <= 0) {
|
|
150
|
+
throw new Error(`Must be positive or the default (-1), got: maxAnswerChars=${limit}`);
|
|
151
|
+
}
|
|
152
|
+
if (result.length > limit) {
|
|
153
|
+
return `The answer is too long (${result.length} characters). Please try a more specific tool query or raise the max_answer_chars parameter.`;
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
isActive() {
|
|
158
|
+
return this.agent.toolIsActive(this.constructor);
|
|
159
|
+
}
|
|
160
|
+
async applyEx(args = {}, options = {}) {
|
|
161
|
+
const { logCall = true, catchExceptions = true, maxAnswerChars = -1 } = options;
|
|
162
|
+
const applyFn = this.getApplyFn();
|
|
163
|
+
const metadata = this.getApplyFnMetadata();
|
|
164
|
+
const validatedArgs = metadata.inputSchema !== undefined ? metadata.inputSchema.parse(args) : args;
|
|
165
|
+
const task = async () => {
|
|
166
|
+
try {
|
|
167
|
+
if (!this.isActive()) {
|
|
168
|
+
return `Error: Tool '${this.getName()}' is not active. Active tools: ${this.agent.getActiveToolNames().join(', ')}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
return `RuntimeError while checking if tool ${this.getName()} is active: ${describeError(error)}`;
|
|
173
|
+
}
|
|
174
|
+
if (logCall) {
|
|
175
|
+
log.info(`${this.getName()}: ${formatDictionary(validatedArgs)}`);
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
if (!this.hasMarker(ToolMarkerDoesNotRequireActiveProject)) {
|
|
179
|
+
const activeProject = this.agent.getActiveProject();
|
|
180
|
+
if (!activeProject) {
|
|
181
|
+
const projects = this.agent.serenaConfig.projectNames;
|
|
182
|
+
return [
|
|
183
|
+
`Error: No active project. Ask the user to provide the project path or to select a project from this list of known projects:`,
|
|
184
|
+
projects.join(', ') || '(none)'
|
|
185
|
+
].join(' ');
|
|
186
|
+
}
|
|
187
|
+
if (this.agent.isUsingLanguageServer() && !this.agent.isLanguageServerRunning()) {
|
|
188
|
+
log.info('Language server is not running. Starting it ...');
|
|
189
|
+
await Promise.resolve(this.agent.resetLanguageServer());
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
let result;
|
|
193
|
+
try {
|
|
194
|
+
const output = await Promise.resolve(applyFn(validatedArgs));
|
|
195
|
+
result = typeof output === 'string' ? output : String(output);
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
if (isSolidLspTerminationError(error)) {
|
|
199
|
+
log.error(`Language server terminated while executing tool (${describeError(error)}). Restarting the language server and retrying ...`);
|
|
200
|
+
await Promise.resolve(this.agent.resetLanguageServer());
|
|
201
|
+
const retryOutput = await Promise.resolve(applyFn(validatedArgs));
|
|
202
|
+
result = typeof retryOutput === 'string' ? retryOutput : String(retryOutput);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
const limited = this._limitLength(result, maxAnswerChars);
|
|
209
|
+
await Promise.resolve(this.agent.recordToolUsageIfEnabled(validatedArgs, limited, this));
|
|
210
|
+
if (logCall) {
|
|
211
|
+
log.info(`Result: ${limited}`);
|
|
212
|
+
}
|
|
213
|
+
try {
|
|
214
|
+
const languageServer = this.agent.languageServer;
|
|
215
|
+
if (languageServer) {
|
|
216
|
+
await Promise.resolve(languageServer.saveCache());
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
log.error(`Error saving language server cache: ${describeError(error)}`);
|
|
221
|
+
}
|
|
222
|
+
return limited;
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (!catchExceptions) {
|
|
226
|
+
throw error;
|
|
227
|
+
}
|
|
228
|
+
const message = `Error executing tool: ${describeError(error)}`;
|
|
229
|
+
log.error(message, error instanceof Error ? error : undefined);
|
|
230
|
+
if (logCall) {
|
|
231
|
+
log.info(`Result: ${message}`);
|
|
232
|
+
}
|
|
233
|
+
return message;
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
const future = this.agent.issueTask(task, { name: this.constructor.name });
|
|
237
|
+
return future.result({ timeout: this.agent.serenaConfig.toolTimeout });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
class EditedFileContextImpl {
|
|
241
|
+
project;
|
|
242
|
+
absolutePath;
|
|
243
|
+
originalContent;
|
|
244
|
+
updatedContent = null;
|
|
245
|
+
constructor(relativePath, agent) {
|
|
246
|
+
const project = agent.getActiveProject();
|
|
247
|
+
if (!project) {
|
|
248
|
+
throw new Error('No active project configured.');
|
|
249
|
+
}
|
|
250
|
+
this.project = project;
|
|
251
|
+
this.absolutePath = path.join(project.projectRoot, relativePath);
|
|
252
|
+
if (!fs.existsSync(this.absolutePath) || !fs.statSync(this.absolutePath).isFile()) {
|
|
253
|
+
throw new Error(`File ${this.absolutePath} does not exist.`);
|
|
254
|
+
}
|
|
255
|
+
const encoding = resolveProjectEncoding(project.projectConfig.encoding);
|
|
256
|
+
this.originalContent = fs.readFileSync(this.absolutePath, { encoding });
|
|
257
|
+
}
|
|
258
|
+
getOriginalContent() {
|
|
259
|
+
return this.originalContent;
|
|
260
|
+
}
|
|
261
|
+
setUpdatedContent(content) {
|
|
262
|
+
this.updatedContent = content;
|
|
263
|
+
}
|
|
264
|
+
async commit() {
|
|
265
|
+
if (this.updatedContent === null) {
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
const encoding = resolveProjectEncoding(this.project.projectConfig.encoding);
|
|
269
|
+
await fs.promises.writeFile(this.absolutePath, this.updatedContent, { encoding });
|
|
270
|
+
log.info(`Updated content written to ${this.absolutePath}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
export class EditedFileContext {
|
|
274
|
+
static async use(relativePath, agent, handler) {
|
|
275
|
+
const context = new EditedFileContextImpl(relativePath, agent);
|
|
276
|
+
const result = await handler(context);
|
|
277
|
+
await context.commit();
|
|
278
|
+
return result;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
class ToolRegistryImpl {
|
|
282
|
+
toolMap = new Map();
|
|
283
|
+
registerToolClass(toolClass) {
|
|
284
|
+
const toolName = toolClass.getNameFromCls();
|
|
285
|
+
if (this.toolMap.has(toolName)) {
|
|
286
|
+
throw new Error(`Duplicate tool name found: ${toolName}. Tool classes must have unique names.`);
|
|
287
|
+
}
|
|
288
|
+
this.toolMap.set(toolName, {
|
|
289
|
+
toolClass,
|
|
290
|
+
isOptional: toolClass.hasMarker(ToolMarkerOptional),
|
|
291
|
+
toolName
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
registerMany(toolClasses) {
|
|
295
|
+
for (const toolClass of toolClasses) {
|
|
296
|
+
this.registerToolClass(toolClass);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
getToolClassByName(toolName) {
|
|
300
|
+
const entry = this.toolMap.get(toolName);
|
|
301
|
+
if (!entry) {
|
|
302
|
+
throw new Error(`Tool ${toolName} is not registered.`);
|
|
303
|
+
}
|
|
304
|
+
return entry.toolClass;
|
|
305
|
+
}
|
|
306
|
+
getAllToolClasses() {
|
|
307
|
+
return Array.from(this.toolMap.values(), (entry) => entry.toolClass);
|
|
308
|
+
}
|
|
309
|
+
getToolClassesDefaultEnabled() {
|
|
310
|
+
return Array.from(this.toolMap.values())
|
|
311
|
+
.filter((entry) => !entry.isOptional)
|
|
312
|
+
.map((entry) => entry.toolClass);
|
|
313
|
+
}
|
|
314
|
+
getToolClassesOptional() {
|
|
315
|
+
return Array.from(this.toolMap.values())
|
|
316
|
+
.filter((entry) => entry.isOptional)
|
|
317
|
+
.map((entry) => entry.toolClass);
|
|
318
|
+
}
|
|
319
|
+
getToolNamesDefaultEnabled() {
|
|
320
|
+
return Array.from(this.toolMap.values())
|
|
321
|
+
.filter((entry) => !entry.isOptional)
|
|
322
|
+
.map((entry) => entry.toolName);
|
|
323
|
+
}
|
|
324
|
+
getToolNamesOptional() {
|
|
325
|
+
return Array.from(this.toolMap.values())
|
|
326
|
+
.filter((entry) => entry.isOptional)
|
|
327
|
+
.map((entry) => entry.toolName);
|
|
328
|
+
}
|
|
329
|
+
getToolNames() {
|
|
330
|
+
return Array.from(this.toolMap.keys());
|
|
331
|
+
}
|
|
332
|
+
isValidToolName(toolName) {
|
|
333
|
+
return this.toolMap.has(toolName);
|
|
334
|
+
}
|
|
335
|
+
printToolOverview(tools, options = {}) {
|
|
336
|
+
let selection = tools;
|
|
337
|
+
if (!selection) {
|
|
338
|
+
if (options.onlyOptional) {
|
|
339
|
+
selection = this.getToolClassesOptional();
|
|
340
|
+
}
|
|
341
|
+
else if (options.includeOptional) {
|
|
342
|
+
selection = this.getAllToolClasses();
|
|
343
|
+
}
|
|
344
|
+
else {
|
|
345
|
+
selection = this.getToolClassesDefaultEnabled();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
const catalog = new Map();
|
|
349
|
+
for (const tool of selection) {
|
|
350
|
+
if (typeof tool === 'function') {
|
|
351
|
+
catalog.set(tool.getNameFromCls(), tool);
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
catalog.set(tool.getName(), tool);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
const sortedNames = Array.from(catalog.keys()).sort();
|
|
358
|
+
for (const toolName of sortedNames) {
|
|
359
|
+
const item = catalog.get(toolName);
|
|
360
|
+
if (!item) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
363
|
+
const toolClass = typeof item === 'function' ? item : item.constructor;
|
|
364
|
+
const description = toolClass.getToolDescription();
|
|
365
|
+
console.log(` * \`${toolName}\`: ${description}`);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
/** @internal */
|
|
369
|
+
resetForTesting() {
|
|
370
|
+
this.toolMap.clear();
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
const ToolRegistrySingleton = singleton(ToolRegistryImpl);
|
|
374
|
+
export { ToolRegistrySingleton as ToolRegistry };
|
|
375
|
+
export function registerToolClass(toolClass) {
|
|
376
|
+
const registry = new ToolRegistrySingleton();
|
|
377
|
+
registry.registerToolClass(toolClass);
|
|
378
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Tool } from './tools_base.js';
|
|
2
|
+
export declare class CheckOnboardingPerformedTool extends Tool {
|
|
3
|
+
static readonly description = "Checks whether project onboarding was already performed.";
|
|
4
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
5
|
+
}
|
|
6
|
+
export declare class OnboardingTool extends Tool {
|
|
7
|
+
static readonly description = "Provides onboarding instructions (project structure, essential tasks, etc.) when onboarding has not been performed.";
|
|
8
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
9
|
+
}
|
|
10
|
+
export declare class ThinkAboutCollectedInformationTool extends Tool {
|
|
11
|
+
static readonly description = "Encourages the agent to reflect on whether the gathered information is sufficient and relevant.";
|
|
12
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare class ThinkAboutTaskAdherenceTool extends Tool {
|
|
15
|
+
static readonly description = "Guides the agent to confirm alignment with the current task before making code changes.";
|
|
16
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
17
|
+
}
|
|
18
|
+
export declare class ThinkAboutWhetherYouAreDoneTool extends Tool {
|
|
19
|
+
static readonly description = "Helps determine whether the requested task is fully completed.";
|
|
20
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
export declare class SummarizeChangesTool extends Tool {
|
|
23
|
+
static readonly markers: Set<"optional">;
|
|
24
|
+
static readonly description = "Provides guidelines for summarizing codebase changes after completing a task.";
|
|
25
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
26
|
+
}
|
|
27
|
+
export declare class PrepareForNewConversationTool extends Tool {
|
|
28
|
+
static readonly description = "Provides instructions to prepare for continuing work in a new conversation context.";
|
|
29
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
30
|
+
}
|
|
31
|
+
export declare class InitialInstructionsTool extends Tool {
|
|
32
|
+
static readonly markers: Set<"does-not-require-active-project" | "optional">;
|
|
33
|
+
static readonly description = "Returns the initial system instructions for the current project when they cannot be provided via the system prompt.";
|
|
34
|
+
apply(_args?: Record<string, unknown>): Promise<string>;
|
|
35
|
+
}
|