botholomew 0.8.9 → 0.9.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "botholomew",
3
- "version": "0.8.9",
3
+ "version": "0.9.4",
4
4
  "description": "An autonomous AI agent for knowledge work — works your task queue while you sleep.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/chat/agent.ts CHANGED
@@ -37,6 +37,7 @@ const CHAT_TOOL_NAMES = new Set([
37
37
  "context_info",
38
38
  "context_refresh",
39
39
  "context_tree",
40
+ "context_list_drives",
40
41
  "search_grep",
41
42
  "search_semantic",
42
43
  "list_threads",
@@ -65,18 +66,16 @@ export async function buildChatSystemPrompt(
65
66
  keywordSource?: string;
66
67
  dbPath?: string;
67
68
  config?: Required<BotholomewConfig>;
69
+ hasMcpTools?: boolean;
68
70
  },
69
71
  ): Promise<string> {
70
- const parts: string[] = [];
71
-
72
- parts.push(...buildMetaHeader(projectDir));
72
+ let prompt = buildMetaHeader(projectDir);
73
73
 
74
74
  const keywordSource = options?.keywordSource?.trim();
75
75
  const taskKeywords = keywordSource ? extractKeywords(keywordSource) : null;
76
76
 
77
- parts.push(...(await loadPersistentContext(projectDir, taskKeywords)));
77
+ prompt += await loadPersistentContext(projectDir, taskKeywords);
78
78
 
79
- // Relevant context from embeddings search
80
79
  const dbPath = options?.dbPath;
81
80
  const config = options?.config;
82
81
  if (dbPath && config?.openai_api_key && keywordSource) {
@@ -87,14 +86,15 @@ export async function buildChatSystemPrompt(
87
86
  );
88
87
 
89
88
  if (results.length > 0) {
90
- parts.push("## Relevant Context");
89
+ prompt += "## Relevant Context\n";
91
90
  for (const r of results) {
92
- const path = r.source_path || r.context_item_id;
93
- parts.push(`### ${r.title} (${path})`);
91
+ const ref =
92
+ r.drive && r.path ? `${r.drive}:${r.path}` : r.context_item_id;
93
+ prompt += `### ${r.title} (${ref})\n`;
94
94
  if (r.chunk_content) {
95
- parts.push(r.chunk_content.slice(0, 1000));
95
+ prompt += `${r.chunk_content.slice(0, 1000)}\n`;
96
96
  }
97
- parts.push("");
97
+ prompt += "\n";
98
98
  }
99
99
  }
100
100
  } catch (err) {
@@ -102,28 +102,30 @@ export async function buildChatSystemPrompt(
102
102
  }
103
103
  }
104
104
 
105
- parts.push("## Instructions");
106
- parts.push(
107
- "You are Botholomew, an AI agent personified by a wise owl. This is your interactive chat interface. Help the user manage tasks, review results from background worker activity, search context, and answer questions.",
108
- );
109
- parts.push(
110
- "You do NOT execute long-running work directly — enqueue tasks for a background worker instead using create_task, and spawn a worker via spawn_worker when the user wants the task run now.",
111
- );
112
- parts.push(
113
- "Use the available tools to look up tasks, threads, schedules, and context when the user asks about them. Context items can be looked up by virtual path or by UUID via `context_info` and refreshed via `context_refresh`.",
114
- );
115
- parts.push(
116
- "When multiple tool calls are independent of each other (i.e., one does not depend on the result of another), call them all in a single response. They will be executed in parallel, which is faster than calling them one at a time.",
117
- );
118
- parts.push(
119
- "You can update the agent's beliefs and goals files when the user asks you to.",
120
- );
121
- parts.push(
122
- "Format your responses using Markdown. Use headings, bold, italic, lists, and code blocks to make your responses clear and well-structured.",
123
- );
124
- parts.push("");
105
+ prompt += `## Instructions
106
+ You are Botholomew, an AI agent personified by a wise owl. This is your interactive chat interface. Help the user manage tasks, review results from background worker activity, search context, and answer questions.
107
+ You do NOT execute long-running work directly enqueue tasks for a background worker instead using create_task, and spawn a worker via spawn_worker when the user wants the task run now.
108
+ Use the available tools to look up tasks, threads, schedules, and context when the user asks about them. Context items live under a drive (disk / url / agent / google-docs / github / …); use \`context_list_drives\` to discover which drives have content, then \`context_tree\`, \`context_info\`, \`context_search\`, or \`context_refresh\` as needed.
109
+ When multiple tool calls are independent of each other (i.e., one does not depend on the result of another), call them all in a single response. They will be executed in parallel, which is faster than calling them one at a time.
110
+ You can update the agent's beliefs and goals files when the user asks you to.
111
+ Format your responses using Markdown. Use headings, bold, italic, lists, and code blocks to make your responses clear and well-structured.
112
+ `;
113
+
114
+ if (options?.hasMcpTools) {
115
+ prompt += `
116
+ ## External Tools (MCP)
117
+
118
+ You have access to external tools via MCP servers. Before calling any MCP tool you haven't used yet this session, you MUST fetch its schema first:
119
+
120
+ 1. Discover tools with \`mcp_search\` (preferred — semantic) or \`mcp_list_tools\`.
121
+ 2. Call \`mcp_info\` with the exact \`server\` and \`tool\` to read the tool's input schema, required fields, and types.
122
+ 3. Only then call \`mcp_exec\` with arguments that conform to that schema.
123
+
124
+ Skip step 2 only if you already called \`mcp_info\` for that exact server+tool earlier in this conversation. Do not guess arguments from the tool's description alone — descriptions omit types and required/optional markers.
125
+ `;
126
+ }
125
127
 
126
- return parts.join("\n");
128
+ return prompt;
127
129
  }
128
130
 
129
131
  export interface ToolEndMeta {
@@ -202,6 +204,7 @@ export async function runChatTurn(input: {
202
204
  keywordSource,
203
205
  dbPath,
204
206
  config,
207
+ hasMcpTools: mcpxClient != null,
205
208
  });
206
209
 
207
210
  fitToContextWindow(messages, systemPrompt, maxInputTokens);