Skip to content

Commit 258f069

Browse files
Add hybrid session management and tool handling capabilities; enhance system prompt for improved context awareness
1 parent 08214d8 commit 258f069

7 files changed

Lines changed: 271 additions & 205 deletions

File tree

src/config/constants.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,27 @@ You operate in the environment mentioned in <SystemInfo> tag.
2121
Please ensure all commands are compatible with this environment.
2222
`
2323

24+
export const COMBINED_SYSTEM_PROMPT = `You are a versatile assistant with full system access for both file editing and command execution.
25+
You are currently operating in ${Deno.cwd()} directory with the following capabilities:
26+
27+
1. File System Access:
28+
- Full access to read and edit files
29+
- All paths should be relative to current directory
30+
- Use './' or '.' for current directory references
31+
- Use relative paths for subdirectories
32+
33+
2. Command Execution:
34+
- Can execute shell commands in the current environment
35+
- Ensure commands are compatible with the system
36+
- Can navigate and manipulate the file system
37+
38+
3. Memory Management:
39+
- Access to system memory via /root/memory.json
40+
- Can add, retrieve, and clear memories
41+
- Use memory for context persistence
42+
43+
Please handle both file operations and command execution in a secure and efficient manner.`
44+
2445
export const API_CONFIG = {
2546
MODEL: "claude-3-5-sonnet-20241022",
2647
INTENT_MODEL: "claude-3-5-haiku-20241022",

src/main.ts

Lines changed: 8 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,13 @@ import {parseArgs} from "jsr:@std/cli/parse-args"
44
import {ensureDir} from "jsr:@std/fs"
55
import {format} from "jsr:@std/datetime"
66
import {crypto} from "jsr:@std/crypto"
7-
import {Anthropic} from "npm:@anthropic-ai/sdk"
87

98
import {setupLogging, log} from "./config/logging.ts"
10-
import {EDITOR_DIR, SESSIONS_DIR, API_CONFIG} from "./config/constants.ts"
9+
import {EDITOR_DIR, SESSIONS_DIR} from "./config/constants.ts"
1110
import {EditorSession} from "./modules/editor/editor_session.ts"
1211
import {BashSession} from "./modules/bash/bash_session.ts"
13-
14-
async function determineIntent(prompt: string): Promise<string> {
15-
const client = new Anthropic({
16-
apiKey: Deno.env.get("ANTHROPIC_API_KEY") ?? "",
17-
})
18-
19-
const message = await client.messages.create({
20-
model: API_CONFIG.INTENT_MODEL,
21-
max_tokens: API_CONFIG.MAX_INTENT_TOKENS,
22-
system: `You have following query from user, determine what is the intent of user.
23-
and based on user's intent and available tools, pick the best tool that can help user.
24-
25-
<AvailableTools>
26-
bash
27-
editor
28-
</AvailableTools>
29-
Instruction,
30-
- Only use the tools mentioned in <AvailableTools> tag.
31-
- If user's intent is not clear, respond with editor.
32-
Only respond with the tool name, avoid yapping.`,
33-
messages: [{
34-
role: "user",
35-
content: prompt,
36-
}],
37-
})
38-
39-
return message.content.find((block) => block.type === "text")?.text ?? "editor"
40-
41-
}
12+
import {HybridSession} from "./modules/hybrid/hybrid_session.ts"
13+
import {determineIntent} from "./utils/intent.ts"
4214

4315
async function main() {
4416
await setupLogging()
@@ -55,16 +27,18 @@ async function main() {
5527
const sessionId = `${format(new Date(), "yyyyMMdd-HHmmss")}-${crypto.randomUUID().slice(0, 6)
5628
}`
5729

58-
const intent = await determineIntent(prompt)
59-
log.debug(`Intent determined: ${intent}`)
60-
const mode = flags.mode || intent
30+
const mode = flags.mode || (flags.mode !== "beta" ? await determineIntent(prompt) : "beta")
31+
log.debug(`Mode selected: ${mode}`)
6132

6233
if (mode === "editor") {
6334
const session = new EditorSession(sessionId)
6435
await session.processEdit(prompt)
6536
} else if (mode === "bash") {
6637
const session = new BashSession(sessionId, flags["no-agi"])
6738
await session.processBashCommand(prompt)
39+
} else if (mode === "beta") {
40+
const session = new HybridSession(sessionId, flags["no-agi"])
41+
await session.process(prompt)
6842
} else {
6943
console.error("Invalid mode specified")
7044
Deno.exit(1)

src/modules/bash/bash_session.ts

Lines changed: 11 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,14 @@
1-
import {BaseSession} from "../../utils/session.ts"
2-
import {BASH_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS} from "../../config/constants.ts"
3-
import {ToolResult} from "../../types/interfaces.ts"
4-
import {log} from "../../config/logging.ts"
5-
import {BashHandlers} from "./handlers.ts"
6-
import {MemoryManager} from "../memory/memory_manager.ts"
1+
import { BaseSession } from "../../utils/session.ts";
2+
import { BASH_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS } from "../../config/constants.ts";
3+
import { log } from "../../config/logging.ts";
4+
import { ToolHandler } from "../../utils/tool_handler.ts";
75

86
export class BashSession extends BaseSession {
9-
private noAgi: boolean
10-
private environment: Record<string, string>
11-
private memoryManager: MemoryManager
12-
13-
private handlers: BashHandlers
7+
private toolHandler: ToolHandler;
148

159
constructor(sessionId?: string, noAgi = false) {
16-
super(sessionId)
17-
this.noAgi = noAgi
18-
this.environment = {...Deno.env.toObject()}
19-
this.handlers = new BashHandlers(noAgi)
20-
this.memoryManager = new MemoryManager()
10+
super(sessionId);
11+
this.toolHandler = new ToolHandler(noAgi);
2112
}
2213

2314
async processBashCommand(bashPrompt: string): Promise<void> {
@@ -74,17 +65,17 @@ System Context:
7465
break
7566
}
7667

77-
const toolResults = await this.processToolCalls(response.content)
68+
const toolResults = await this.toolHandler.processToolCalls(response.content);
7869

7970
if (toolResults.length) {
8071
this.messages.push({
8172
role: "user",
8273
content: [toolResults[0].output],
83-
})
74+
});
8475

8576
if (toolResults[0].output.is_error) {
86-
log.error(`Error: ${toolResults[0].output.content[0].text}`)
87-
break
77+
log.error(`Error: ${toolResults[0].output.content[0].text}`);
78+
break;
8879
}
8980
}
9081
}
@@ -95,77 +86,4 @@ System Context:
9586
throw error
9687
}
9788
}
98-
99-
private async processToolCalls(content: any[]): Promise<ToolResult[]> {
100-
const results: ToolResult[] = []
101-
102-
for (const toolCall of content) {
103-
if (toolCall.type === "tool_use") {
104-
let result
105-
let isError = false
106-
107-
switch (toolCall.name) {
108-
case "bash": {
109-
110-
log.info(`Bash tool call input: ${JSON.stringify(toolCall.input)}`)
111-
result = await this.handlers.handleBashCommand(toolCall.input)
112-
isError = "error" in result
113-
const toolResultContent = isError
114-
? [{type: "text", text: result.error}]
115-
: [{type: "text", text: result.content || "Command executed successfully."}]
116-
117-
results.push({
118-
tool_call_id: toolCall.id,
119-
output: {
120-
type: "tool_result",
121-
content: toolResultContent,
122-
tool_use_id: toolCall.id,
123-
is_error: isError,
124-
},
125-
})
126-
break
127-
}
128-
case "add_memory":
129-
result = await this.memoryManager.addMemory(toolCall.input.content)
130-
results.push({
131-
tool_call_id: toolCall.id,
132-
output: {
133-
type: "tool_result",
134-
content: [{type: "text", text: result.content}],
135-
tool_use_id: toolCall.id,
136-
is_error: false,
137-
},
138-
})
139-
break
140-
case "get_memories":
141-
result = await this.memoryManager.getMemories()
142-
results.push({
143-
tool_call_id: toolCall.id,
144-
output: {
145-
type: "tool_result",
146-
content: [{type: "text", text: JSON.stringify(result)}],
147-
tool_use_id: toolCall.id,
148-
is_error: false,
149-
},
150-
})
151-
break
152-
case "clear_memories":
153-
await this.memoryManager.clearMemories()
154-
result = {message: "Memories cleared successfully"}
155-
results.push({
156-
tool_call_id: toolCall.id,
157-
output: {
158-
type: "tool_result",
159-
content: [{type: "text", text: JSON.stringify(result)}],
160-
tool_use_id: toolCall.id,
161-
is_error: false,
162-
},
163-
})
164-
break
165-
}
166-
}
167-
}
168-
169-
return results
170-
}
17189
}
Lines changed: 31 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,124 +1,77 @@
1-
import {BaseSession} from "../../utils/session.ts"
2-
import {EDITOR_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS} from "../../config/constants.ts"
3-
import {ToolResult} from "../../types/interfaces.ts"
4-
import {log} from "../../config/logging.ts"
5-
import {EditorHandlers} from "./handlers.ts"
6-
import {MemoryManager} from "../memory/memory_manager.ts"
1+
import { BaseSession } from "../../utils/session.ts";
2+
import { EDITOR_SYSTEM_PROMPT, API_CONFIG, MEMORY_TOOLS } from "../../config/constants.ts";
3+
import { log } from "../../config/logging.ts";
4+
import { ToolHandler } from "../../utils/tool_handler.ts";
75

86
export class EditorSession extends BaseSession {
9-
private handlers: EditorHandlers
10-
private memoryManager: MemoryManager
7+
private toolHandler: ToolHandler;
118

129
constructor(sessionId?: string) {
13-
super(sessionId)
14-
this.handlers = new EditorHandlers()
15-
this.memoryManager = new MemoryManager()
10+
super(sessionId);
11+
this.toolHandler = new ToolHandler();
1612
}
1713

1814
async processEdit(prompt: string): Promise<void> {
1915
try {
2016
const message = {
2117
role: "user",
22-
content: [{type: "text", text: prompt}],
23-
}
24-
this.messages = [message]
18+
content: [{ type: "text", text: prompt }],
19+
};
20+
this.messages = [message];
2521

26-
log.info(`User input: ${JSON.stringify(message)}`)
22+
log.info(`User input: ${JSON.stringify(message)}`);
2723

2824
while (true) {
2925
const response = await this.client.beta.messages.create({
3026
model: API_CONFIG.MODEL,
3127
max_tokens: API_CONFIG.MAX_TOKENS,
3228
messages: this.messages,
3329
tools: [
34-
{type: "text_editor_20241022", name: "str_replace_editor"},
35-
...MEMORY_TOOLS
30+
{ type: "text_editor_20241022", name: "str_replace_editor" },
31+
...MEMORY_TOOLS,
3632
],
3733
system: EDITOR_SYSTEM_PROMPT,
3834
betas: ["computer-use-2024-10-22"],
39-
})
35+
});
4036

41-
const inputTokens = response.usage?.input_tokens ?? 0
42-
const outputTokens = response.usage?.output_tokens ?? 0
43-
log.info(`API usage: input_tokens=${inputTokens}, output_tokens=${outputTokens}`)
44-
this.logger.updateTokenUsage(inputTokens, outputTokens)
37+
const inputTokens = response.usage?.input_tokens ?? 0;
38+
const outputTokens = response.usage?.output_tokens ?? 0;
39+
log.info(`API usage: input_tokens=${inputTokens}, output_tokens=${outputTokens}`);
40+
this.logger.updateTokenUsage(inputTokens, outputTokens);
4541

4642
const responseContent = response.content.map((block) =>
47-
block.type === "text" ? {type: "text", text: block.text} : block
48-
)
43+
block.type === "text" ? { type: "text", text: block.text } : block
44+
);
4945

50-
this.messages.push({role: "assistant", content: responseContent})
46+
this.messages.push({ role: "assistant", content: responseContent });
5147

5248
if (response.stop_reason !== "tool_use") {
53-
console.log(response.content.find((block) => block.type === "text")?.text ?? "editor")
54-
break
49+
console.log(response.content.find((block) => block.type === "text")?.text ?? "editor");
50+
break;
5551
}
5652

57-
const toolResults = await this.processToolCalls(response.content)
53+
const toolResults = await this.toolHandler.processToolCalls(response.content);
5854

5955
if (toolResults?.length) {
6056
this.messages.push({
6157
role: "user",
6258
content: [toolResults[0].output],
63-
})
59+
});
6460

6561
if (toolResults[0].output.is_error) {
66-
log.error(`Error: ${toolResults[0].output.content[0].text}`)
67-
break
62+
log.error(`Error: ${toolResults[0].output.content[0].text}`);
63+
break;
6864
}
6965
}
7066
}
7167

72-
this.logger.logTotalCost()
68+
this.logger.logTotalCost();
7369
} catch (error) {
74-
log.error(`Error in processEdit: ${error instanceof Error ? error.message : String(error)}`)
70+
log.error(`Error in processEdit: ${error instanceof Error ? error.message : String(error)}`);
7571
if (error instanceof Error && error.stack) {
76-
log.error(error.stack)
77-
}
78-
throw error
79-
}
80-
}
81-
82-
private async processToolCalls(content: any[]): Promise<ToolResult[]> {
83-
const results: ToolResult[] = []
84-
85-
for (const toolCall of content) {
86-
if (toolCall.type === "tool_use") {
87-
let result
88-
let isError = false
89-
90-
switch (toolCall.name) {
91-
case "str_replace_editor":
92-
result = await this.handlers.handleTextEditorTool(toolCall.input)
93-
isError = "error" in result
94-
break
95-
case "add_memory":
96-
result = await this.memoryManager.addMemory(toolCall.input.content)
97-
break
98-
case "get_memories":
99-
result = await this.memoryManager.getMemories()
100-
break
101-
case "clear_memories":
102-
await this.memoryManager.clearMemories()
103-
result = {message: "Memories cleared successfully"}
104-
break
105-
}
106-
107-
results.push({
108-
tool_call_id: toolCall.id,
109-
output: {
110-
type: "tool_result",
111-
content: [{
112-
type: "text",
113-
text: JSON.stringify(result)
114-
}],
115-
tool_use_id: toolCall.id,
116-
is_error: isError,
117-
},
118-
})
72+
log.error(error.stack);
11973
}
74+
throw error;
12075
}
121-
122-
return results
12376
}
12477
}

0 commit comments

Comments
 (0)