Skip to content

Commit 1ad1bef

Browse files
Add export functionality and enhance session logging; update dependencies and interfaces
1 parent d534778 commit 1ad1bef

14 files changed

Lines changed: 407 additions & 96 deletions

File tree

deno.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/commands/export.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import {parseArgs} from "jsr:@std/cli/parse-args"
2+
import {PromptDatabase} from "../modules/db/database.ts"
3+
import {log} from "../config/logging.ts"
4+
import {parseFlagForHelp} from "../utils/functions.ts"
5+
import {format} from "jsr:@std/datetime"
6+
import {join} from "jsr:@std/path"
7+
import {ensureDir} from "jsr:@std/fs"
8+
9+
export async function handleExport(args: string[]) {
10+
const db = new PromptDatabase()
11+
const commandFlags = {
12+
string: ["session"],
13+
boolean: ["help"],
14+
}
15+
16+
const flags = parseArgs(args, commandFlags)
17+
18+
if (flags.help) {
19+
console.log(parseFlagForHelp(commandFlags))
20+
return
21+
}
22+
23+
if (!flags.session) {
24+
console.error("Session ID is required. Use --session <id>")
25+
return
26+
}
27+
28+
try {
29+
const markdown = await db.exportSessionToMarkdown(flags.session)
30+
31+
// Create exports directory
32+
const exportDir = join(Deno.cwd(), "exports")
33+
await ensureDir(exportDir)
34+
35+
// Generate filename with timestamp
36+
const filename = `session_${flags.session}_${format(new Date(), "yyyyMMdd_HHmmss")}.md`
37+
const filepath = join(exportDir, filename)
38+
39+
// Write markdown to file
40+
await Deno.writeTextFile(filepath, markdown)
41+
42+
console.log(`Session log exported to: ${filepath}`)
43+
} catch (error) {
44+
log.error(`Error exporting session: ${error}`)
45+
console.error(`Failed to export session: ${error}`)
46+
}
47+
}

src/commands/history.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {log} from "../config/logging.ts"
55
import {parseFlagForHelp} from "../utils/functions.ts"
66

77
export async function handleHistory(args: string[]) {
8-
98
const db = new PromptDatabase()
109
const commandFlags = {
1110
string: ["view", "limit"],
@@ -28,13 +27,16 @@ export async function handleHistory(args: string[]) {
2827
const entry = db.getPromptById(id)
2928

3029
if (entry) {
31-
HistoryViewer.displayEntry(entry)
30+
let sessionLogs = undefined
31+
if (entry.session_id) {
32+
sessionLogs = await db.getSessionLogs(entry.session_id)
33+
}
34+
HistoryViewer.displayEntry(entry, sessionLogs)
3235
} else {
3336
console.error(`No entry found with ID ${id}`)
3437
}
3538
} else {
3639
const limit = parseInt(flags.limit || "10")
37-
3840
const entries: PromptEntry[] = db.listPrompts(isNaN(limit) ? 10 : limit)
3941
HistoryViewer.displayHistory(entries)
4042
}

src/config/constants.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export const LOGS_DIR = join(homedir(), ".ComputerUseAgent", "logs")
99
export const DEFAULT_TOOLS_CONFIG_PATH = join(homedir(), ".ComputerUseAgent", "settings.json")
1010
export const MEMORY_PATH = "/root/memory.json"
1111

12-
export const DEFAULT_EDITOR = Deno.env.get("EDITOR") ?? "nano";
12+
export const DEFAULT_EDITOR = Deno.env.get("EDITOR") ?? "nano"
1313

1414
export const EDITOR_SYSTEM_PROMPT = Deno.env.get("EDITOR_SYSTEM_PROMPT") ??
1515
`You are a helpful assistant that helps users edit and work with text files.
@@ -26,8 +26,20 @@ You operate in the environment mentioned in <SystemInfo> tag.
2626
Please ensure all commands are compatible with this environment.
2727
`
2828

29+
export const PLANNER_SYSTEM_PROMPT = `
30+
You prepare plans for an agentic system.
31+
You will receive the user request, current system information and available tools in their respective tags.
32+
Use this information to create a step by step plan for the agent to follow.
33+
Evaluate the user's request, if this is a simple request like a greeting, requesting information or advice which can be done without any tools simply respond with 'Reply to the user.'.
34+
However for anything more complex. Reflect on system information and available tools to create a step by step plan that agent can follow.
35+
take a note that the agent will always have access to running shell commands and file system operations,
36+
with that in mind suggest any additional tools which are optimal for the task.
37+
You should respond with detailed JSON plan having the following shape:
38+
[{step:1,action:'Action to be taken to achieve the goal', tools:['tool1','tool2']},"..."]
39+
ONLY Respond in JSON without any codefences or any other details
40+
`
2941
export const COMBINED_SYSTEM_PROMPT = `
30-
You are a versatile assistant with full system access for both file editing and command execution.
42+
You are a versatile assistant with full system access.
3143
You are currently operating in ${Deno.cwd()} directory.
3244
3345
You have access to following tools and capabilities:

src/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {HybridSession} from "./modules/hybrid/hybrid_session.ts"
1313
import {parseFlagForHelp} from "./utils/functions.ts"
1414
import {handleHistory} from "./commands/history.ts"
1515
import {handleSettings} from "./commands/settings.ts"
16+
import {handleExport} from "./commands/export.ts"
1617
import {loadUserSettings} from "./config/settings.ts"
1718
import {openInEditor} from "./commands/editor.ts"
1819

@@ -39,6 +40,9 @@ async function main() {
3940
} else if (flags._[0] === "settings") {
4041
await handleSettings(Deno.args)
4142
return
43+
} else if (flags._[0] === "export") {
44+
await handleExport(Deno.args)
45+
return
4246
} else if (flags._[0] === "help") {
4347
console.log(parseFlagForHelp(argParseConfig))
4448
return

src/modules/bash/bash_session.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ System Context:
3838

3939
log.info(`User input: ${JSON.stringify(apiMessage)}`)
4040

41+
let result = ""
4142
while (true) {
4243
const response = await this.client.beta.messages.create({
4344
model: API_CONFIG.MODEL,
@@ -60,6 +61,11 @@ System Context:
6061

6162
this.messages.push({role: "assistant", content: responseContent})
6263

64+
if (response.content.find((block) => block.type === "text")?.text) {
65+
const text = response.content.find((block) => block.type === "text")?.text || ""
66+
result += text + "\n"
67+
}
68+
6369
if (response.stop_reason !== "tool_use") {
6470
console.log(response.content.find((block) => block.type === "text")?.text ?? "bash")
6571
break
@@ -81,8 +87,10 @@ System Context:
8187
}
8288

8389
this.logger.logTotalCost()
90+
await this.logInteraction('bash', bashPrompt, result, this.sessionId)
8491
} catch (error) {
8592
log.error(`Error in processBashCommand: ${error}`)
93+
await this.logInteraction('bash', bashPrompt, `${error}`, this.sessionId)
8694
throw error
8795
}
8896
}

src/modules/bash/handlers.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@ export class BashHandlers {
4141
// First attempt: Try running the command directly
4242
const directProcess = new Deno.Command(command.split(" ")[0], {
4343
args: command.split(" ").slice(1),
44-
env: this.environment,
44+
4545
stdout: "piped",
46+
4647
stderr: "piped",
4748
})
4849
const result = await directProcess.output()

src/modules/cli/history_viewer.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
import {blue, bold, green, magenta, yellow} from "jsr:@std/fmt/colors"
1+
import {blue, bold, green, magenta, yellow, red} from "jsr:@std/fmt/colors"
22
import {Table} from "table"
3+
import type {SessionLogEntry} from "../db/database.ts"
34

45
export class HistoryViewer {
56
static displayHistory(entries: Array<{
@@ -10,6 +11,7 @@ export class HistoryViewer {
1011
result: string
1112
tokens_used: number
1213
cost: number
14+
session_id?: string
1315
}>) {
1416
console.clear()
1517

@@ -19,6 +21,7 @@ export class HistoryViewer {
1921
bold("ID"),
2022
bold("Time"),
2123
bold("Mode"),
24+
bold("Session"),
2225
bold("Prompt"),
2326
bold("Cost ($)")
2427
]
@@ -27,6 +30,7 @@ export class HistoryViewer {
2730
blue(entry.id.toString()),
2831
green(entry.timestamp),
2932
yellow(entry.mode),
33+
entry.session_id ? magenta(entry.session_id) : "-",
3034
entry.prompt.slice(0, 50) + (entry.prompt.length > 50 ? "..." : ""),
3135
magenta(entry.cost.toFixed(6))
3236
])
@@ -43,13 +47,17 @@ export class HistoryViewer {
4347
result: string
4448
tokens_used: number
4549
cost: number
46-
}) {
50+
session_id?: string
51+
}, sessionLogs?: SessionLogEntry[]) {
4752
console.clear()
4853
console.log(bold("\nPrompt Details:"))
4954
console.log("═".repeat(50))
5055
console.log(blue(`ID: ${entry.id}`))
5156
console.log(green(`Time: ${entry.timestamp}`))
5257
console.log(yellow(`Mode: ${entry.mode}`))
58+
if (entry.session_id) {
59+
console.log(magenta(`Session: ${entry.session_id}`))
60+
}
5361
console.log(magenta(`Tokens: ${entry.tokens_used}`))
5462
console.log(magenta(`Cost: $${entry.cost.toFixed(6)}`))
5563
console.log("\n" + bold("Prompt:"))
@@ -58,6 +66,27 @@ export class HistoryViewer {
5866
console.log("\n" + bold("Result:"))
5967
console.log("─".repeat(50))
6068
console.log(entry.result)
69+
70+
if (sessionLogs?.length) {
71+
console.log("\n" + bold("Session Steps:"))
72+
console.log("═".repeat(50))
73+
for (const log of sessionLogs) {
74+
console.log(blue(`\nStep ${log.step_number}: ${log.step_description}`))
75+
console.log(green(`Time: ${log.timestamp}`))
76+
console.log(`Tools: ${Array.isArray(log.tools_used) ? log.tools_used.join(", ") :
77+
typeof log.tools_used === 'string' ? JSON.parse(log.tools_used).join(", ") : log.tools_used}`)
78+
if (log.result) {
79+
console.log("\nResult:")
80+
console.log(log.result)
81+
}
82+
if (log.error) {
83+
console.log("\nError:")
84+
console.log(red(log.error))
85+
}
86+
console.log("─".repeat(50))
87+
}
88+
}
89+
6190
console.log("\n")
6291
}
6392
}

0 commit comments

Comments
 (0)