@openvole/paw-ollama 0.1.0 → 0.2.0

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/README.md ADDED
@@ -0,0 +1,40 @@
1
+ # @openvole/paw-ollama
2
+
3
+ **Brain Paw powered by Ollama for local LLM inference.**
4
+
5
+ [![npm](https://img.shields.io/npm/v/@openvole/paw-ollama)](https://www.npmjs.com/package/@openvole/paw-ollama)
6
+
7
+ Part of [OpenVole](https://github.com/openvole/openvole) — the microkernel AI agent framework.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install @openvole/paw-ollama
13
+ ```
14
+
15
+ ## Config
16
+
17
+ ```json
18
+ {
19
+ "name": "@openvole/paw-ollama",
20
+ "allow": {
21
+ "network": ["127.0.0.1"],
22
+ "env": ["OLLAMA_MODEL", "OLLAMA_HOST"]
23
+ }
24
+ }
25
+ ```
26
+
27
+ ## Environment Variables
28
+
29
+ | Variable | Description |
30
+ |----------|-------------|
31
+ | `OLLAMA_MODEL` | Model name to use (e.g. `llama3`) |
32
+ | `OLLAMA_HOST` | Ollama server address (default `http://127.0.0.1:11434`) |
33
+
34
+ ## Brain
35
+
36
+ Implements the Think phase — receives the conversation context and registered tools, returns the next assistant message and any tool calls. Uses a locally running Ollama instance.
37
+
38
+ ## License
39
+
40
+ [MIT](https://github.com/openvole/pawhub/blob/main/LICENSE)
package/dist/index.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // src/index.ts
2
2
  import { definePaw } from "@openvole/paw-sdk";
3
3
 
4
+ // src/paw.ts
5
+ import * as fs from "fs/promises";
6
+ import * as path from "path";
7
+
4
8
  // src/ollama.ts
5
9
  import { Ollama } from "ollama";
6
10
  var OllamaClient = class {
@@ -16,8 +20,60 @@ var OllamaClient = class {
16
20
  /**
17
21
  * Build the system prompt from active skills and available tools.
18
22
  */
19
- buildSystemPrompt(activeSkills, availableTools) {
20
- const parts = ["You are an AI agent powered by OpenVole."];
23
+ buildSystemPrompt(activeSkills, availableTools, metadata, identityContext2, customBrainPrompt2) {
24
+ const now = /* @__PURE__ */ new Date();
25
+ const runtimeContext = `## Current Context
26
+ - Date: ${now.toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" })}
27
+ - Time: ${now.toLocaleTimeString("en-US", { hour12: true })}
28
+ - Platform: ${process.platform}
29
+ - Model: ${this.model}`;
30
+ const basePrompt = customBrainPrompt2 ?? `You are an AI agent powered by OpenVole. You accomplish tasks by using tools step by step.
31
+
32
+ ## How to Work
33
+ 1. Read the conversation history first \u2014 short user messages like an email or "yes" are answers to your previous questions
34
+ 2. Break complex tasks into clear steps and execute them one at a time
35
+ 3. After each tool call, examine the result carefully before deciding the next action
36
+ 4. Never repeat the same tool call if it already succeeded \u2014 move to the next step
37
+ 5. If a tool returns an error, try a different approach or different parameters
38
+ 6. When you read important information (API docs, instructions, credentials), save it to workspace or memory immediately
39
+ 7. When you have enough information to respond, do so directly \u2014 don't keep searching
40
+ 8. If you cannot complete a task (missing credentials, access denied), explain exactly what you need and stop
41
+ 9. Your responses are for the user only \u2014 never include tool calls, function names, system commands, JSON, or any technical execution details in your response text. Execute tools silently via function calling, then respond with the human-readable result.
42
+ 10. Complete all tool calls before responding. If you need to save data, fetch a URL, or perform any action \u2014 do it as a tool call first, then respond after the results are in.
43
+
44
+ ## Data Management
45
+ - **Vault** (vault_store/get): ALL sensitive data \u2014 emails, passwords, API keys, tokens, credentials, usernames, handles, personal identifiers. ALWAYS use vault for these, NEVER memory or workspace.
46
+ - **Memory** (memory_write/read): General knowledge, non-sensitive facts, preferences, summaries
47
+ - **Workspace** (workspace_write/read): Files, documents, downloaded content, API docs, drafts
48
+ - **Session history**: Recent conversation \u2014 automatically available, review it before each response
49
+
50
+ ## Recurring Tasks
51
+ When the user asks you to do something regularly, repeatedly, or on a schedule:
52
+ - **schedule_task**: Use this for tasks with a specific interval (e.g. "post every 6 hours", "check every 30 minutes"). Creates an automatic timer \u2014 no heartbeat needed.
53
+ - **heartbeat_write**: Use this ONLY for open-ended checks with no specific interval (e.g. "keep an eye on server status"). These run on the global heartbeat timer.
54
+ - Use ONE or the OTHER \u2014 never both for the same task. If you use schedule_task, do NOT also add it to HEARTBEAT.md.
55
+ - Do NOT just save recurring task requests to memory \u2014 that won't make them happen.
56
+
57
+ ## Safety
58
+ - Never attempt to bypass access controls or escalate permissions
59
+ - Always ask for confirmation before performing destructive or irreversible actions
60
+ - Store credentials and personal identifiers ONLY in the vault \u2014 never in memory or workspace`;
61
+ const parts = [basePrompt, "", runtimeContext];
62
+ if (identityContext2) {
63
+ parts.push("");
64
+ parts.push(identityContext2);
65
+ }
66
+ if (metadata?.sessionHistory && typeof metadata.sessionHistory === "string") {
67
+ parts.push("");
68
+ parts.push("## Conversation History");
69
+ parts.push("Previous messages in this session. Use this to understand the current context and follow-up messages:");
70
+ parts.push(metadata.sessionHistory);
71
+ }
72
+ if (metadata?.memory && typeof metadata.memory === "string") {
73
+ parts.push("");
74
+ parts.push("## Agent Memory");
75
+ parts.push(metadata.memory);
76
+ }
21
77
  if (activeSkills.length > 0) {
22
78
  parts.push("");
23
79
  parts.push("## Available Skills");
@@ -70,17 +126,20 @@ var OllamaClient = class {
70
126
  * Convert ToolSummary[] to Ollama Tool[] for function calling.
71
127
  */
72
128
  convertTools(tools) {
73
- return tools.map((tool) => ({
74
- type: "function",
75
- function: {
76
- name: tool.name,
77
- description: tool.description,
78
- parameters: {
79
- type: "object",
80
- properties: {}
129
+ return tools.map((tool) => {
130
+ const params = tool.parameters;
131
+ return {
132
+ type: "function",
133
+ function: {
134
+ name: tool.name,
135
+ description: tool.description,
136
+ parameters: params ?? {
137
+ type: "object",
138
+ properties: {}
139
+ }
81
140
  }
82
- }
83
- }));
141
+ };
142
+ });
84
143
  }
85
144
  /**
86
145
  * Send a chat request to Ollama and return the raw response.
@@ -88,6 +147,9 @@ var OllamaClient = class {
88
147
  async chat(systemPrompt, messages, tools) {
89
148
  const ollamaMessages = this.convertMessages(systemPrompt, messages);
90
149
  const ollamaTools = this.convertTools(tools);
150
+ console.log(
151
+ `[paw-ollama] chat request \u2014 model: ${this.model}, messages: ${ollamaMessages.length}, tools: ${ollamaTools.length}`
152
+ );
91
153
  return this.client.chat({
92
154
  model: this.model,
93
155
  messages: ollamaMessages,
@@ -111,6 +173,42 @@ var OllamaClient = class {
111
173
 
112
174
  // src/paw.ts
113
175
  var client;
176
+ var identityContext;
177
+ var customBrainPrompt;
178
+ async function loadBrainPrompt() {
179
+ try {
180
+ const content = await fs.readFile(
181
+ path.resolve(process.cwd(), ".openvole", "BRAIN.md"),
182
+ "utf-8"
183
+ );
184
+ if (content.trim()) {
185
+ console.log("[paw-ollama] loaded custom BRAIN.md prompt");
186
+ return content.trim();
187
+ }
188
+ } catch {
189
+ }
190
+ return void 0;
191
+ }
192
+ async function loadIdentityFiles() {
193
+ const openvoleDir = path.resolve(process.cwd(), ".openvole");
194
+ const files = [
195
+ { name: "SOUL.md", section: "Agent Identity" },
196
+ { name: "USER.md", section: "User Profile" },
197
+ { name: "AGENT.md", section: "Agent Rules" }
198
+ ];
199
+ const parts = [];
200
+ for (const file of files) {
201
+ try {
202
+ const content = await fs.readFile(path.join(openvoleDir, file.name), "utf-8");
203
+ if (content.trim()) {
204
+ parts.push(`## ${file.section}
205
+ ${content.trim()}`);
206
+ }
207
+ } catch {
208
+ }
209
+ }
210
+ return parts.join("\n\n");
211
+ }
114
212
  function getClient() {
115
213
  if (!client) {
116
214
  const host = process.env.OLLAMA_HOST || "http://localhost:11434";
@@ -130,7 +228,10 @@ var paw = {
130
228
  try {
131
229
  const systemPrompt = ollamaClient.buildSystemPrompt(
132
230
  context.activeSkills,
133
- context.availableTools
231
+ context.availableTools,
232
+ context.metadata,
233
+ identityContext,
234
+ customBrainPrompt
134
235
  );
135
236
  const response = await ollamaClient.chat(
136
237
  systemPrompt,
@@ -142,6 +243,9 @@ var paw = {
142
243
  `[paw-ollama] think completed in ${durationMs}ms (model: ${ollamaClient.getModel()})`
143
244
  );
144
245
  const actions = ollamaClient.parseToolCalls(response);
246
+ console.log(
247
+ `[paw-ollama] response \u2014 role: ${response.message.role}, content: ${(response.message.content || "").substring(0, 100)}, tool_calls: ${response.message.tool_calls?.length ?? 0}, actions: ${actions.length}`
248
+ );
145
249
  if (actions.length > 0) {
146
250
  return {
147
251
  actions,
@@ -157,9 +261,14 @@ var paw = {
157
261
  } catch (error) {
158
262
  const durationMs = Date.now() - start;
159
263
  const message = error instanceof Error ? error.message : String(error);
264
+ const stack = error instanceof Error ? error.stack : void 0;
160
265
  console.error(
161
266
  `[paw-ollama] think failed after ${durationMs}ms: ${message}`
162
267
  );
268
+ if (stack) console.error(`[paw-ollama] stack: ${stack}`);
269
+ console.error(
270
+ `[paw-ollama] model: ${ollamaClient.getModel()}, host: ${process.env.OLLAMA_HOST || "http://localhost:11434"}, messages: ${context.messages.length}, tools: ${context.availableTools.length}`
271
+ );
163
272
  const isConnectionError = message.includes("ECONNREFUSED") || message.includes("fetch failed") || message.includes("ENOTFOUND");
164
273
  return {
165
274
  actions: [],
@@ -170,6 +279,11 @@ var paw = {
170
279
  },
171
280
  async onLoad() {
172
281
  const ollamaClient = getClient();
282
+ customBrainPrompt = await loadBrainPrompt();
283
+ identityContext = await loadIdentityFiles();
284
+ if (identityContext) {
285
+ console.log("[paw-ollama] loaded identity files (SOUL.md, USER.md, AGENT.md)");
286
+ }
173
287
  console.log(
174
288
  `[paw-ollama] loaded \u2014 model: ${ollamaClient.getModel()}, host: ${process.env.OLLAMA_HOST || "http://localhost:11434"}`
175
289
  );
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/ollama.ts","../src/paw.ts"],"sourcesContent":["import { definePaw } from '@openvole/paw-sdk'\nimport { paw } from './paw.js'\n\nexport default definePaw(paw)\n","import { Ollama, type ChatResponse, type Message, type Tool } from 'ollama'\nimport type {\n\tAgentMessage,\n\tActiveSkill,\n\tPlannedAction,\n\tToolSummary,\n} from '@openvole/paw-sdk'\n\nexport class OllamaClient {\n\tprivate client: Ollama\n\tprivate model: string\n\n\tconstructor(\n\t\thost: string = 'http://localhost:11434',\n\t\tmodel: string = 'qwen3:latest',\n\t) {\n\t\tthis.client = new Ollama({ host })\n\t\tthis.model = model\n\t}\n\n\tgetModel(): string {\n\t\treturn this.model\n\t}\n\n\t/**\n\t * Build the system prompt from active skills and available tools.\n\t */\n\tbuildSystemPrompt(\n\t\tactiveSkills: ActiveSkill[],\n\t\tavailableTools: ToolSummary[],\n\t): string {\n\t\tconst parts: string[] = ['You are an AI agent powered by OpenVole.']\n\n\t\tif (activeSkills.length > 0) {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Available Skills')\n\t\t\tparts.push(\n\t\t\t\t'The following skills are available. Use the skill_read tool to load full instructions when a skill is relevant to the current task.',\n\t\t\t)\n\t\t\tfor (const skill of activeSkills) {\n\t\t\t\tparts.push(`- **${skill.name}**: ${skill.description}`)\n\t\t\t}\n\t\t}\n\n\t\tif (availableTools.length > 0) {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Available Tools')\n\t\t\tparts.push(\n\t\t\t\t'You have access to the following tools. Use function calling to invoke them when needed.',\n\t\t\t)\n\t\t\tfor (const tool of availableTools) {\n\t\t\t\tparts.push(`- **${tool.name}** (from ${tool.pawName}): ${tool.description}`)\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join('\\n')\n\t}\n\n\t/**\n\t * Convert AgentMessage[] to Ollama Message[].\n\t */\n\tconvertMessages(\n\t\tsystemPrompt: string,\n\t\tmessages: AgentMessage[],\n\t): Message[] {\n\t\tconst result: Message[] = [{ role: 'system', content: systemPrompt }]\n\n\t\tfor (const msg of messages) {\n\t\t\tswitch (msg.role) {\n\t\t\t\tcase 'user':\n\t\t\t\t\tresult.push({ role: 'user', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'brain':\n\t\t\t\t\tresult.push({ role: 'assistant', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'tool_result':\n\t\t\t\t\tresult.push({ role: 'tool', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'error':\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trole: 'tool',\n\t\t\t\t\t\tcontent: `Error: ${msg.content}`,\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Convert ToolSummary[] to Ollama Tool[] for function calling.\n\t */\n\tconvertTools(tools: ToolSummary[]): Tool[] {\n\t\treturn tools.map((tool) => ({\n\t\t\ttype: 'function',\n\t\t\tfunction: {\n\t\t\t\tname: tool.name,\n\t\t\t\tdescription: tool.description,\n\t\t\t\tparameters: {\n\t\t\t\t\ttype: 'object',\n\t\t\t\t\tproperties: {},\n\t\t\t\t},\n\t\t\t},\n\t\t}))\n\t}\n\n\t/**\n\t * Send a chat request to Ollama and return the raw response.\n\t */\n\tasync chat(\n\t\tsystemPrompt: string,\n\t\tmessages: AgentMessage[],\n\t\ttools: ToolSummary[],\n\t): Promise<ChatResponse> {\n\t\tconst ollamaMessages = this.convertMessages(systemPrompt, messages)\n\t\tconst ollamaTools = this.convertTools(tools)\n\n\t\treturn this.client.chat({\n\t\t\tmodel: this.model,\n\t\t\tmessages: ollamaMessages,\n\t\t\ttools: ollamaTools.length > 0 ? ollamaTools : undefined,\n\t\t\tstream: false,\n\t\t})\n\t}\n\n\t/**\n\t * Extract PlannedAction[] from Ollama tool_calls.\n\t */\n\tparseToolCalls(response: ChatResponse): PlannedAction[] {\n\t\tif (!response.message.tool_calls || response.message.tool_calls.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn response.message.tool_calls.map((call) => ({\n\t\t\ttool: call.function.name,\n\t\t\tparams: call.function.arguments,\n\t\t}))\n\t}\n}\n","import type { PawDefinition, AgentContext, AgentPlan } from '@openvole/paw-sdk'\nimport { OllamaClient } from './ollama.js'\n\nlet client: OllamaClient | undefined\n\nfunction getClient(): OllamaClient {\n\tif (!client) {\n\t\tconst host = process.env.OLLAMA_HOST || 'http://localhost:11434'\n\t\tconst model = process.env.OLLAMA_MODEL || 'qwen3:latest'\n\t\tclient = new OllamaClient(host, model)\n\t}\n\treturn client\n}\n\nexport const paw: PawDefinition = {\n\tname: '@openvole/paw-ollama',\n\tversion: '0.1.0',\n\tdescription: 'Brain Paw powered by Ollama for local LLM inference',\n\tbrain: true,\n\n\tasync think(context: AgentContext): Promise<AgentPlan> {\n\t\tconst ollamaClient = getClient()\n\t\tconst start = Date.now()\n\n\t\ttry {\n\t\t\tconst systemPrompt = ollamaClient.buildSystemPrompt(\n\t\t\t\tcontext.activeSkills,\n\t\t\t\tcontext.availableTools,\n\t\t\t)\n\n\t\t\tconst response = await ollamaClient.chat(\n\t\t\t\tsystemPrompt,\n\t\t\t\tcontext.messages,\n\t\t\t\tcontext.availableTools,\n\t\t\t)\n\n\t\t\tconst durationMs = Date.now() - start\n\t\t\tconsole.log(\n\t\t\t\t`[paw-ollama] think completed in ${durationMs}ms (model: ${ollamaClient.getModel()})`,\n\t\t\t)\n\n\t\t\tconst actions = ollamaClient.parseToolCalls(response)\n\n\t\t\tif (actions.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tactions,\n\t\t\t\t\texecution: 'sequential',\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst text = response.message.content || ''\n\n\t\t\t// If the model produced a text response, return it as done\n\t\t\treturn {\n\t\t\t\tactions: [],\n\t\t\t\tresponse: text,\n\t\t\t\tdone: true,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst durationMs = Date.now() - start\n\t\t\tconst message =\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\tconsole.error(\n\t\t\t\t`[paw-ollama] think failed after ${durationMs}ms: ${message}`,\n\t\t\t)\n\n\t\t\t// Check for connection errors (Ollama not running)\n\t\t\tconst isConnectionError =\n\t\t\t\tmessage.includes('ECONNREFUSED') ||\n\t\t\t\tmessage.includes('fetch failed') ||\n\t\t\t\tmessage.includes('ENOTFOUND')\n\n\t\t\treturn {\n\t\t\t\tactions: [],\n\t\t\t\tresponse: isConnectionError\n\t\t\t\t\t? 'Ollama is not running or unreachable. Please start Ollama and try again.'\n\t\t\t\t\t: `Error communicating with Ollama: ${message}`,\n\t\t\t\tdone: true,\n\t\t\t}\n\t\t}\n\t},\n\n\tasync onLoad() {\n\t\tconst ollamaClient = getClient()\n\t\tconsole.log(\n\t\t\t`[paw-ollama] loaded — model: ${ollamaClient.getModel()}, host: ${process.env.OLLAMA_HOST || 'http://localhost:11434'}`,\n\t\t)\n\t},\n\n\tasync onUnload() {\n\t\tclient = undefined\n\t\tconsole.log('[paw-ollama] unloaded')\n\t},\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/paw.ts","../src/ollama.ts"],"sourcesContent":["import { definePaw } from '@openvole/paw-sdk'\nimport { paw } from './paw.js'\n\nexport default definePaw(paw)\n","import * as fs from 'node:fs/promises'\nimport * as path from 'node:path'\nimport type { PawDefinition, AgentContext, AgentPlan } from '@openvole/paw-sdk'\nimport { OllamaClient } from './ollama.js'\n\nlet client: OllamaClient | undefined\n\n/** Cached identity files — loaded once on startup */\nlet identityContext: string | undefined\n\n/** Custom brain prompt from BRAIN.md — overrides default system prompt if present */\nlet customBrainPrompt: string | undefined\n\n/** Load BRAIN.md from .openvole/ — if it exists, it replaces the default system prompt */\nasync function loadBrainPrompt(): Promise<string | undefined> {\n\ttry {\n\t\tconst content = await fs.readFile(\n\t\t\tpath.resolve(process.cwd(), '.openvole', 'BRAIN.md'),\n\t\t\t'utf-8',\n\t\t)\n\t\tif (content.trim()) {\n\t\t\tconsole.log('[paw-ollama] loaded custom BRAIN.md prompt')\n\t\t\treturn content.trim()\n\t\t}\n\t} catch {\n\t\t// No BRAIN.md — use default\n\t}\n\treturn undefined\n}\n\n/** Load identity files from .openvole/ (AGENT.md, USER.md, SOUL.md) */\nasync function loadIdentityFiles(): Promise<string> {\n\tconst openvoleDir = path.resolve(process.cwd(), '.openvole')\n\tconst files = [\n\t\t{ name: 'SOUL.md', section: 'Agent Identity' },\n\t\t{ name: 'USER.md', section: 'User Profile' },\n\t\t{ name: 'AGENT.md', section: 'Agent Rules' },\n\t]\n\n\tconst parts: string[] = []\n\tfor (const file of files) {\n\t\ttry {\n\t\t\tconst content = await fs.readFile(path.join(openvoleDir, file.name), 'utf-8')\n\t\t\tif (content.trim()) {\n\t\t\t\tparts.push(`## ${file.section}\\n${content.trim()}`)\n\t\t\t}\n\t\t} catch {\n\t\t\t// File doesn't exist — skip\n\t\t}\n\t}\n\n\treturn parts.join('\\n\\n')\n}\n\nfunction getClient(): OllamaClient {\n\tif (!client) {\n\t\tconst host = process.env.OLLAMA_HOST || 'http://localhost:11434'\n\t\tconst model = process.env.OLLAMA_MODEL || 'qwen3:latest'\n\t\tclient = new OllamaClient(host, model)\n\t}\n\treturn client\n}\n\nexport const paw: PawDefinition = {\n\tname: '@openvole/paw-ollama',\n\tversion: '0.1.0',\n\tdescription: 'Brain Paw powered by Ollama for local LLM inference',\n\tbrain: true,\n\n\tasync think(context: AgentContext): Promise<AgentPlan> {\n\t\tconst ollamaClient = getClient()\n\t\tconst start = Date.now()\n\n\t\ttry {\n\t\t\tconst systemPrompt = ollamaClient.buildSystemPrompt(\n\t\t\t\tcontext.activeSkills,\n\t\t\t\tcontext.availableTools,\n\t\t\t\tcontext.metadata,\n\t\t\t\tidentityContext,\n\t\t\t\tcustomBrainPrompt,\n\t\t\t)\n\n\t\t\tconst response = await ollamaClient.chat(\n\t\t\t\tsystemPrompt,\n\t\t\t\tcontext.messages,\n\t\t\t\tcontext.availableTools,\n\t\t\t)\n\n\t\t\tconst durationMs = Date.now() - start\n\t\t\tconsole.log(\n\t\t\t\t`[paw-ollama] think completed in ${durationMs}ms (model: ${ollamaClient.getModel()})`,\n\t\t\t)\n\n\t\t\tconst actions = ollamaClient.parseToolCalls(response)\n\n\t\t\tconsole.log(\n\t\t\t\t`[paw-ollama] response — role: ${response.message.role}, content: ${(response.message.content || '').substring(0, 100)}, tool_calls: ${response.message.tool_calls?.length ?? 0}, actions: ${actions.length}`,\n\t\t\t)\n\n\t\t\tif (actions.length > 0) {\n\t\t\t\treturn {\n\t\t\t\t\tactions,\n\t\t\t\t\texecution: 'sequential',\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst text = response.message.content || ''\n\n\t\t\t// If the model produced a text response, return it as done\n\t\t\treturn {\n\t\t\t\tactions: [],\n\t\t\t\tresponse: text,\n\t\t\t\tdone: true,\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst durationMs = Date.now() - start\n\t\t\tconst message =\n\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\tconst stack =\n\t\t\t\terror instanceof Error ? error.stack : undefined\n\t\t\tconsole.error(\n\t\t\t\t`[paw-ollama] think failed after ${durationMs}ms: ${message}`,\n\t\t\t)\n\t\t\tif (stack) console.error(`[paw-ollama] stack: ${stack}`)\n\t\t\t// Log request details for debugging\n\t\t\tconsole.error(\n\t\t\t\t`[paw-ollama] model: ${ollamaClient.getModel()}, host: ${process.env.OLLAMA_HOST || 'http://localhost:11434'}, messages: ${context.messages.length}, tools: ${context.availableTools.length}`,\n\t\t\t)\n\n\t\t\t// Check for connection errors (Ollama not running)\n\t\t\tconst isConnectionError =\n\t\t\t\tmessage.includes('ECONNREFUSED') ||\n\t\t\t\tmessage.includes('fetch failed') ||\n\t\t\t\tmessage.includes('ENOTFOUND')\n\n\t\t\treturn {\n\t\t\t\tactions: [],\n\t\t\t\tresponse: isConnectionError\n\t\t\t\t\t? 'Ollama is not running or unreachable. Please start Ollama and try again.'\n\t\t\t\t\t: `Error communicating with Ollama: ${message}`,\n\t\t\t\tdone: true,\n\t\t\t}\n\t\t}\n\t},\n\n\tasync onLoad() {\n\t\tconst ollamaClient = getClient()\n\t\tcustomBrainPrompt = await loadBrainPrompt()\n\t\tidentityContext = await loadIdentityFiles()\n\t\tif (identityContext) {\n\t\t\tconsole.log('[paw-ollama] loaded identity files (SOUL.md, USER.md, AGENT.md)')\n\t\t}\n\t\tconsole.log(\n\t\t\t`[paw-ollama] loaded — model: ${ollamaClient.getModel()}, host: ${process.env.OLLAMA_HOST || 'http://localhost:11434'}`,\n\t\t)\n\t},\n\n\tasync onUnload() {\n\t\tclient = undefined\n\t\tconsole.log('[paw-ollama] unloaded')\n\t},\n}\n","import { Ollama, type ChatResponse, type Message, type Tool } from 'ollama'\nimport type {\n\tAgentMessage,\n\tActiveSkill,\n\tPlannedAction,\n\tToolSummary,\n} from '@openvole/paw-sdk'\n\nexport class OllamaClient {\n\tprivate client: Ollama\n\tprivate model: string\n\n\tconstructor(\n\t\thost: string = 'http://localhost:11434',\n\t\tmodel: string = 'qwen3:latest',\n\t) {\n\t\tthis.client = new Ollama({ host })\n\t\tthis.model = model\n\t}\n\n\tgetModel(): string {\n\t\treturn this.model\n\t}\n\n\t/**\n\t * Build the system prompt from active skills and available tools.\n\t */\n\tbuildSystemPrompt(\n\t\tactiveSkills: ActiveSkill[],\n\t\tavailableTools: ToolSummary[],\n\t\tmetadata?: Record<string, unknown>,\n\t\tidentityContext?: string,\n\t\tcustomBrainPrompt?: string,\n\t): string {\n\t\tconst now = new Date()\n\t\tconst runtimeContext = `## Current Context\n- Date: ${now.toLocaleDateString('en-US', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' })}\n- Time: ${now.toLocaleTimeString('en-US', { hour12: true })}\n- Platform: ${process.platform}\n- Model: ${this.model}`\n\n\t\t// Use custom BRAIN.md if provided, otherwise use default prompt\n\t\tconst basePrompt = customBrainPrompt ?? `You are an AI agent powered by OpenVole. You accomplish tasks by using tools step by step.\n\n## How to Work\n1. Read the conversation history first — short user messages like an email or \"yes\" are answers to your previous questions\n2. Break complex tasks into clear steps and execute them one at a time\n3. After each tool call, examine the result carefully before deciding the next action\n4. Never repeat the same tool call if it already succeeded — move to the next step\n5. If a tool returns an error, try a different approach or different parameters\n6. When you read important information (API docs, instructions, credentials), save it to workspace or memory immediately\n7. When you have enough information to respond, do so directly — don't keep searching\n8. If you cannot complete a task (missing credentials, access denied), explain exactly what you need and stop\n9. Your responses are for the user only — never include tool calls, function names, system commands, JSON, or any technical execution details in your response text. Execute tools silently via function calling, then respond with the human-readable result.\n10. Complete all tool calls before responding. If you need to save data, fetch a URL, or perform any action — do it as a tool call first, then respond after the results are in.\n\n## Data Management\n- **Vault** (vault_store/get): ALL sensitive data — emails, passwords, API keys, tokens, credentials, usernames, handles, personal identifiers. ALWAYS use vault for these, NEVER memory or workspace.\n- **Memory** (memory_write/read): General knowledge, non-sensitive facts, preferences, summaries\n- **Workspace** (workspace_write/read): Files, documents, downloaded content, API docs, drafts\n- **Session history**: Recent conversation — automatically available, review it before each response\n\n## Recurring Tasks\nWhen the user asks you to do something regularly, repeatedly, or on a schedule:\n- **schedule_task**: Use this for tasks with a specific interval (e.g. \"post every 6 hours\", \"check every 30 minutes\"). Creates an automatic timer — no heartbeat needed.\n- **heartbeat_write**: Use this ONLY for open-ended checks with no specific interval (e.g. \"keep an eye on server status\"). These run on the global heartbeat timer.\n- Use ONE or the OTHER — never both for the same task. If you use schedule_task, do NOT also add it to HEARTBEAT.md.\n- Do NOT just save recurring task requests to memory — that won't make them happen.\n\n## Safety\n- Never attempt to bypass access controls or escalate permissions\n- Always ask for confirmation before performing destructive or irreversible actions\n- Store credentials and personal identifiers ONLY in the vault — never in memory or workspace`\n\n\t\tconst parts: string[] = [basePrompt, '', runtimeContext]\n\n\t\t// Inject identity context (SOUL.md, USER.md, AGENT.md) if available\n\t\tif (identityContext) {\n\t\t\tparts.push('')\n\t\t\tparts.push(identityContext)\n\t\t}\n\n\t\t// Inject session history if available — this is critical for conversation continuity\n\t\tif (metadata?.sessionHistory && typeof metadata.sessionHistory === 'string') {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Conversation History')\n\t\t\tparts.push('Previous messages in this session. Use this to understand the current context and follow-up messages:')\n\t\t\tparts.push(metadata.sessionHistory)\n\t\t}\n\n\t\t// Inject memory if available\n\t\tif (metadata?.memory && typeof metadata.memory === 'string') {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Agent Memory')\n\t\t\tparts.push(metadata.memory)\n\t\t}\n\n\t\tif (activeSkills.length > 0) {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Available Skills')\n\t\t\tparts.push(\n\t\t\t\t'The following skills are available. Use the skill_read tool to load full instructions when a skill is relevant to the current task.',\n\t\t\t)\n\t\t\tfor (const skill of activeSkills) {\n\t\t\t\tparts.push(`- **${skill.name}**: ${skill.description}`)\n\t\t\t}\n\t\t}\n\n\t\tif (availableTools.length > 0) {\n\t\t\tparts.push('')\n\t\t\tparts.push('## Available Tools')\n\t\t\tparts.push(\n\t\t\t\t'You have access to the following tools. Use function calling to invoke them when needed.',\n\t\t\t)\n\t\t\tfor (const tool of availableTools) {\n\t\t\t\tparts.push(`- **${tool.name}** (from ${tool.pawName}): ${tool.description}`)\n\t\t\t}\n\t\t}\n\n\t\treturn parts.join('\\n')\n\t}\n\n\t/**\n\t * Convert AgentMessage[] to Ollama Message[].\n\t */\n\tconvertMessages(\n\t\tsystemPrompt: string,\n\t\tmessages: AgentMessage[],\n\t): Message[] {\n\t\tconst result: Message[] = [{ role: 'system', content: systemPrompt }]\n\n\t\tfor (const msg of messages) {\n\t\t\tswitch (msg.role) {\n\t\t\t\tcase 'user':\n\t\t\t\t\tresult.push({ role: 'user', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'brain':\n\t\t\t\t\tresult.push({ role: 'assistant', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'tool_result':\n\t\t\t\t\tresult.push({ role: 'tool', content: msg.content })\n\t\t\t\t\tbreak\n\t\t\t\tcase 'error':\n\t\t\t\t\tresult.push({\n\t\t\t\t\t\trole: 'tool',\n\t\t\t\t\t\tcontent: `Error: ${msg.content}`,\n\t\t\t\t\t})\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\treturn result\n\t}\n\n\t/**\n\t * Convert ToolSummary[] to Ollama Tool[] for function calling.\n\t */\n\tconvertTools(tools: ToolSummary[]): Tool[] {\n\t\treturn tools.map((tool) => {\n\t\t\t// Parameters are pre-converted to JSON Schema by the core\n\t\t\tconst params = (tool as { parameters?: Record<string, unknown> }).parameters\n\n\t\t\treturn {\n\t\t\t\ttype: 'function',\n\t\t\t\tfunction: {\n\t\t\t\t\tname: tool.name,\n\t\t\t\t\tdescription: tool.description,\n\t\t\t\t\tparameters: params ?? {\n\t\t\t\t\t\ttype: 'object',\n\t\t\t\t\t\tproperties: {},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t}\n\t\t})\n\t}\n\n\t/**\n\t * Send a chat request to Ollama and return the raw response.\n\t */\n\tasync chat(\n\t\tsystemPrompt: string,\n\t\tmessages: AgentMessage[],\n\t\ttools: ToolSummary[],\n\t): Promise<ChatResponse> {\n\t\tconst ollamaMessages = this.convertMessages(systemPrompt, messages)\n\t\tconst ollamaTools = this.convertTools(tools)\n\n\t\tconsole.log(\n\t\t\t`[paw-ollama] chat request — model: ${this.model}, messages: ${ollamaMessages.length}, tools: ${ollamaTools.length}`,\n\t\t)\n\t\treturn this.client.chat({\n\t\t\tmodel: this.model,\n\t\t\tmessages: ollamaMessages,\n\t\t\ttools: ollamaTools.length > 0 ? ollamaTools : undefined,\n\t\t\tstream: false,\n\t\t})\n\t}\n\n\t/**\n\t * Extract PlannedAction[] from Ollama tool_calls.\n\t */\n\tparseToolCalls(response: ChatResponse): PlannedAction[] {\n\t\tif (!response.message.tool_calls || response.message.tool_calls.length === 0) {\n\t\t\treturn []\n\t\t}\n\n\t\treturn response.message.tool_calls.map((call) => ({\n\t\t\ttool: call.function.name,\n\t\t\tparams: call.function.arguments,\n\t\t}))\n\t}\n}\n"],"mappings":"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","names":["identityContext","customBrainPrompt"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openvole/paw-ollama",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Brain Paw powered by Ollama for local LLM inference",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -11,6 +11,10 @@
11
11
  "types": "./dist/index.d.ts"
12
12
  }
13
13
  },
14
+ "scripts": {
15
+ "build": "tsup",
16
+ "typecheck": "tsc --noEmit"
17
+ },
14
18
  "dependencies": {
15
19
  "ollama": "^0.5.0"
16
20
  },
@@ -25,7 +29,8 @@
25
29
  },
26
30
  "files": [
27
31
  "dist",
28
- "vole-paw.json"
32
+ "vole-paw.json",
33
+ "README.md"
29
34
  ],
30
35
  "license": "MIT",
31
36
  "repository": {
@@ -42,9 +47,5 @@
42
47
  ],
43
48
  "peerDependencies": {
44
49
  "@openvole/paw-sdk": "^0.1.0"
45
- },
46
- "scripts": {
47
- "build": "tsup",
48
- "typecheck": "tsc --noEmit"
49
50
  }
50
- }
51
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 OpenVole
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.