@hasna/oldpal 0.1.7 → 0.1.8

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/dist/index.js CHANGED
@@ -29187,6 +29187,194 @@ class FilesystemTools {
29187
29187
  };
29188
29188
  }
29189
29189
 
29190
+ // packages/core/src/tools/web.ts
29191
+ class WebFetchTool {
29192
+ static tool = {
29193
+ name: "web_fetch",
29194
+ description: "Fetch content from a URL and return the text content. Useful for reading web pages, documentation, API responses, etc.",
29195
+ parameters: {
29196
+ type: "object",
29197
+ properties: {
29198
+ url: {
29199
+ type: "string",
29200
+ description: "The URL to fetch content from"
29201
+ },
29202
+ extract_type: {
29203
+ type: "string",
29204
+ description: 'What to extract: "text" for readable text, "html" for raw HTML, "json" for JSON response',
29205
+ enum: ["text", "html", "json"],
29206
+ default: "text"
29207
+ },
29208
+ timeout: {
29209
+ type: "number",
29210
+ description: "Timeout in milliseconds (default: 30000)"
29211
+ }
29212
+ },
29213
+ required: ["url"]
29214
+ }
29215
+ };
29216
+ static executor = async (input) => {
29217
+ const url = input.url;
29218
+ const extractType = input.extract_type || "text";
29219
+ const timeout = input.timeout || 30000;
29220
+ try {
29221
+ const parsedUrl = new URL(url);
29222
+ const hostname = parsedUrl.hostname;
29223
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || hostname.startsWith("172.")) {
29224
+ return "Error: Cannot fetch from local/private network addresses for security reasons";
29225
+ }
29226
+ const controller = new AbortController;
29227
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
29228
+ const response = await fetch(url, {
29229
+ signal: controller.signal,
29230
+ headers: {
29231
+ "User-Agent": "oldpal/1.0 (AI Assistant)",
29232
+ Accept: extractType === "json" ? "application/json" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
29233
+ }
29234
+ });
29235
+ clearTimeout(timeoutId);
29236
+ if (!response.ok) {
29237
+ return `Error: HTTP ${response.status} ${response.statusText}`;
29238
+ }
29239
+ const contentType = response.headers.get("content-type") || "";
29240
+ if (extractType === "json") {
29241
+ try {
29242
+ const json = await response.json();
29243
+ return JSON.stringify(json, null, 2);
29244
+ } catch {
29245
+ return "Error: Response is not valid JSON";
29246
+ }
29247
+ }
29248
+ const html = await response.text();
29249
+ if (extractType === "html") {
29250
+ const maxLength2 = 50000;
29251
+ if (html.length > maxLength2) {
29252
+ return html.slice(0, maxLength2) + `
29253
+
29254
+ [Content truncated...]`;
29255
+ }
29256
+ return html;
29257
+ }
29258
+ const text = extractReadableText(html);
29259
+ const maxLength = 30000;
29260
+ if (text.length > maxLength) {
29261
+ return text.slice(0, maxLength) + `
29262
+
29263
+ [Content truncated...]`;
29264
+ }
29265
+ return text || "No readable content found on page";
29266
+ } catch (error) {
29267
+ if (error instanceof Error) {
29268
+ if (error.name === "AbortError") {
29269
+ return `Error: Request timed out after ${timeout}ms`;
29270
+ }
29271
+ return `Error: ${error.message}`;
29272
+ }
29273
+ return `Error: ${String(error)}`;
29274
+ }
29275
+ };
29276
+ }
29277
+
29278
+ class WebSearchTool {
29279
+ static tool = {
29280
+ name: "web_search",
29281
+ description: "Search the web using DuckDuckGo and return results. Useful for finding current information, documentation, news, etc.",
29282
+ parameters: {
29283
+ type: "object",
29284
+ properties: {
29285
+ query: {
29286
+ type: "string",
29287
+ description: "The search query"
29288
+ },
29289
+ max_results: {
29290
+ type: "number",
29291
+ description: "Maximum number of results to return (default: 5, max: 10)"
29292
+ }
29293
+ },
29294
+ required: ["query"]
29295
+ }
29296
+ };
29297
+ static executor = async (input) => {
29298
+ const query = input.query;
29299
+ const maxResults = Math.min(input.max_results || 5, 10);
29300
+ try {
29301
+ const searchUrl = `https://html.duckduckgo.com/html/?q=${encodeURIComponent(query)}`;
29302
+ const response = await fetch(searchUrl, {
29303
+ headers: {
29304
+ "User-Agent": "oldpal/1.0 (AI Assistant)",
29305
+ Accept: "text/html"
29306
+ }
29307
+ });
29308
+ if (!response.ok) {
29309
+ return `Error: Search request failed with HTTP ${response.status}`;
29310
+ }
29311
+ const html = await response.text();
29312
+ const results = parseDuckDuckGoResults(html, maxResults);
29313
+ if (results.length === 0) {
29314
+ return `No results found for "${query}"`;
29315
+ }
29316
+ let output = `Search results for "${query}":
29317
+
29318
+ `;
29319
+ for (let i = 0;i < results.length; i++) {
29320
+ const r = results[i];
29321
+ output += `${i + 1}. ${r.title}
29322
+ `;
29323
+ output += ` ${r.url}
29324
+ `;
29325
+ if (r.snippet) {
29326
+ output += ` ${r.snippet}
29327
+ `;
29328
+ }
29329
+ output += `
29330
+ `;
29331
+ }
29332
+ return output.trim();
29333
+ } catch (error) {
29334
+ return `Error: ${error instanceof Error ? error.message : String(error)}`;
29335
+ }
29336
+ };
29337
+ }
29338
+ function extractReadableText(html) {
29339
+ let text = html.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, "").replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "").replace(/<noscript[^>]*>[\s\S]*?<\/noscript>/gi, "").replace(/<nav[^>]*>[\s\S]*?<\/nav>/gi, "").replace(/<footer[^>]*>[\s\S]*?<\/footer>/gi, "").replace(/<header[^>]*>[\s\S]*?<\/header>/gi, "");
29340
+ text = text.replace(/<\/?(p|div|br|h[1-6]|li|tr|blockquote)[^>]*>/gi, `
29341
+ `).replace(/<\/?[^>]+>/g, " ").replace(/&nbsp;/gi, " ").replace(/&amp;/gi, "&").replace(/&lt;/gi, "<").replace(/&gt;/gi, ">").replace(/&quot;/gi, '"').replace(/&#39;/gi, "'").replace(/\s+/g, " ").replace(/\n\s*\n/g, `
29342
+
29343
+ `).trim();
29344
+ return text;
29345
+ }
29346
+ function parseDuckDuckGoResults(html, maxResults) {
29347
+ const results = [];
29348
+ const resultRegex = /<a[^>]*class="result__a"[^>]*href="([^"]*)"[^>]*>([^<]*)<\/a>[\s\S]*?<a[^>]*class="result__snippet"[^>]*>([^<]*)/gi;
29349
+ let match;
29350
+ while ((match = resultRegex.exec(html)) !== null && results.length < maxResults) {
29351
+ const url = decodeURIComponent(match[1].replace(/\/l\/\?uddg=/, "").split("&")[0]);
29352
+ const title = match[2].trim();
29353
+ const snippet = match[3].trim().replace(/&[^;]+;/g, " ");
29354
+ if (url && title && !url.startsWith("//duckduckgo.com")) {
29355
+ results.push({ title, url, snippet });
29356
+ }
29357
+ }
29358
+ if (results.length === 0) {
29359
+ const simpleRegex = /<a[^>]*href="(https?:\/\/[^"]+)"[^>]*class="[^"]*result[^"]*"[^>]*>([^<]+)/gi;
29360
+ while ((match = simpleRegex.exec(html)) !== null && results.length < maxResults) {
29361
+ const url = match[1];
29362
+ const title = match[2].trim();
29363
+ if (url && title) {
29364
+ results.push({ title, url, snippet: "" });
29365
+ }
29366
+ }
29367
+ }
29368
+ return results;
29369
+ }
29370
+
29371
+ class WebTools {
29372
+ static registerAll(registry) {
29373
+ registry.register(WebFetchTool.tool, WebFetchTool.executor);
29374
+ registry.register(WebSearchTool.tool, WebSearchTool.executor);
29375
+ }
29376
+ }
29377
+
29190
29378
  // packages/core/src/skills/loader.ts
29191
29379
  import { join as join3 } from "path";
29192
29380
  import { homedir as homedir2 } from "os";
@@ -29605,6 +29793,7 @@ class AgentLoop {
29605
29793
  this.llmClient = await createLLMClient(this.config.llm);
29606
29794
  this.toolRegistry.register(BashTool.tool, BashTool.executor);
29607
29795
  FilesystemTools.registerAll(this.toolRegistry);
29796
+ WebTools.registerAll(this.toolRegistry);
29608
29797
  await this.connectorBridge.discover(this.config.connectors);
29609
29798
  this.connectorBridge.registerAll(this.toolRegistry);
29610
29799
  await this.skillLoader.loadAll(this.cwd);
@@ -30158,7 +30347,7 @@ function parseMarkdown(text) {
30158
30347
 
30159
30348
  // packages/terminal/src/components/Messages.tsx
30160
30349
  var jsx_dev_runtime3 = __toESM(require_jsx_dev_runtime(), 1);
30161
- function Messages4({ messages, currentResponse, currentToolCall, lastToolResult }) {
30350
+ function Messages4({ messages, currentResponse, currentToolCall, lastToolResult, activityLog = [] }) {
30162
30351
  const visibleMessages = messages.slice(-15);
30163
30352
  return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30164
30353
  flexDirection: "column",
@@ -30166,7 +30355,37 @@ function Messages4({ messages, currentResponse, currentToolCall, lastToolResult
30166
30355
  visibleMessages.map((message) => /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(MessageBubble, {
30167
30356
  message
30168
30357
  }, message.id, false, undefined, this)),
30169
- currentToolCall && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30358
+ activityLog.map((entry) => {
30359
+ if (entry.type === "tool_call" && entry.toolCall) {
30360
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30361
+ marginY: 1,
30362
+ children: [
30363
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
30364
+ dimColor: true,
30365
+ children: "\u25D0 "
30366
+ }, undefined, false, undefined, this),
30367
+ /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
30368
+ dimColor: true,
30369
+ children: formatToolCall(entry.toolCall)
30370
+ }, undefined, false, undefined, this)
30371
+ ]
30372
+ }, entry.id, true, undefined, this);
30373
+ }
30374
+ if (entry.type === "tool_result" && entry.toolResult) {
30375
+ return /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30376
+ marginLeft: 2,
30377
+ children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
30378
+ dimColor: true,
30379
+ children: [
30380
+ "\u2192 ",
30381
+ truncate(entry.toolResult.content, 100)
30382
+ ]
30383
+ }, undefined, true, undefined, this)
30384
+ }, entry.id, false, undefined, this);
30385
+ }
30386
+ return null;
30387
+ }),
30388
+ currentToolCall && !activityLog.some((e) => e.toolCall?.id === currentToolCall.id) && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30170
30389
  marginY: 1,
30171
30390
  children: [
30172
30391
  /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
@@ -30179,7 +30398,7 @@ function Messages4({ messages, currentResponse, currentToolCall, lastToolResult
30179
30398
  }, undefined, false, undefined, this)
30180
30399
  ]
30181
30400
  }, undefined, true, undefined, this),
30182
- lastToolResult && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30401
+ lastToolResult && !activityLog.some((e) => e.toolResult?.toolCallId === lastToolResult.toolCallId) && /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Box_default, {
30183
30402
  marginY: 1,
30184
30403
  marginLeft: 2,
30185
30404
  children: /* @__PURE__ */ jsx_dev_runtime3.jsxDEV(Text, {
@@ -30391,8 +30610,11 @@ function App2({ cwd: cwd2 }) {
30391
30610
  const [isInitializing, setIsInitializing] = import_react25.useState(true);
30392
30611
  const [error, setError] = import_react25.useState(null);
30393
30612
  const [messageQueue, setMessageQueue] = import_react25.useState([]);
30613
+ const [activityLog, setActivityLog] = import_react25.useState([]);
30394
30614
  const responseRef = import_react25.useRef("");
30395
30615
  const clientRef = import_react25.useRef(null);
30616
+ const toolCallsRef = import_react25.useRef([]);
30617
+ const toolResultsRef = import_react25.useRef([]);
30396
30618
  const processQueue = import_react25.useCallback(async () => {
30397
30619
  if (!clientRef.current || messageQueue.length === 0)
30398
30620
  return;
@@ -30407,9 +30629,12 @@ function App2({ cwd: cwd2 }) {
30407
30629
  setMessages((prev) => [...prev, userMessage]);
30408
30630
  setCurrentResponse("");
30409
30631
  responseRef.current = "";
30632
+ toolCallsRef.current = [];
30633
+ toolResultsRef.current = [];
30410
30634
  setError(null);
30411
30635
  setCurrentToolCall(undefined);
30412
30636
  setLastToolResult(undefined);
30637
+ setActivityLog([]);
30413
30638
  setIsProcessing(true);
30414
30639
  await clientRef.current.send(nextMessage);
30415
30640
  }, [messageQueue]);
@@ -30423,27 +30648,51 @@ function App2({ cwd: cwd2 }) {
30423
30648
  responseRef.current += chunk.content;
30424
30649
  setCurrentResponse(responseRef.current);
30425
30650
  } else if (chunk.type === "tool_use" && chunk.toolCall) {
30651
+ toolCallsRef.current.push(chunk.toolCall);
30652
+ setActivityLog((prev) => [
30653
+ ...prev,
30654
+ {
30655
+ id: generateId(),
30656
+ type: "tool_call",
30657
+ toolCall: chunk.toolCall,
30658
+ timestamp: now()
30659
+ }
30660
+ ]);
30426
30661
  setCurrentToolCall(chunk.toolCall);
30427
30662
  setLastToolResult(undefined);
30428
30663
  } else if (chunk.type === "tool_result" && chunk.toolResult) {
30664
+ toolResultsRef.current.push(chunk.toolResult);
30665
+ setActivityLog((prev) => [
30666
+ ...prev,
30667
+ {
30668
+ id: generateId(),
30669
+ type: "tool_result",
30670
+ toolResult: chunk.toolResult,
30671
+ timestamp: now()
30672
+ }
30673
+ ]);
30429
30674
  setLastToolResult(chunk.toolResult);
30430
30675
  setCurrentToolCall(undefined);
30431
30676
  } else if (chunk.type === "error" && chunk.error) {
30432
30677
  setError(chunk.error);
30433
30678
  setIsProcessing(false);
30434
30679
  } else if (chunk.type === "done") {
30435
- if (responseRef.current) {
30680
+ if (responseRef.current || toolCallsRef.current.length > 0) {
30436
30681
  setMessages((prev) => [
30437
30682
  ...prev,
30438
30683
  {
30439
30684
  id: generateId(),
30440
30685
  role: "assistant",
30441
30686
  content: responseRef.current,
30442
- timestamp: now()
30687
+ timestamp: now(),
30688
+ toolCalls: toolCallsRef.current.length > 0 ? [...toolCallsRef.current] : undefined,
30689
+ toolResults: toolResultsRef.current.length > 0 ? [...toolResultsRef.current] : undefined
30443
30690
  }
30444
30691
  ]);
30445
30692
  setCurrentResponse("");
30446
30693
  responseRef.current = "";
30694
+ toolCallsRef.current = [];
30695
+ toolResultsRef.current = [];
30447
30696
  }
30448
30697
  setCurrentToolCall(undefined);
30449
30698
  setLastToolResult(undefined);
@@ -30550,9 +30799,12 @@ function App2({ cwd: cwd2 }) {
30550
30799
  setMessages((prev) => [...prev, userMessage]);
30551
30800
  setCurrentResponse("");
30552
30801
  responseRef.current = "";
30802
+ toolCallsRef.current = [];
30803
+ toolResultsRef.current = [];
30553
30804
  setError(null);
30554
30805
  setCurrentToolCall(undefined);
30555
30806
  setLastToolResult(undefined);
30807
+ setActivityLog([]);
30556
30808
  setIsProcessing(true);
30557
30809
  await client.send(trimmedInput);
30558
30810
  }, [client, isProcessing]);
@@ -30573,7 +30825,8 @@ function App2({ cwd: cwd2 }) {
30573
30825
  messages,
30574
30826
  currentResponse: isProcessing ? currentResponse : undefined,
30575
30827
  currentToolCall,
30576
- lastToolResult
30828
+ lastToolResult,
30829
+ activityLog: isProcessing ? activityLog : []
30577
30830
  }, undefined, false, undefined, this),
30578
30831
  messageQueue.length > 0 && /* @__PURE__ */ jsx_dev_runtime6.jsxDEV(Box_default, {
30579
30832
  marginY: 1,
@@ -30626,7 +30879,7 @@ var options = {
30626
30879
  help: args.includes("--help") || args.includes("-h")
30627
30880
  };
30628
30881
  if (options.version) {
30629
- console.log("oldpal v0.1.7");
30882
+ console.log("oldpal v0.1.8");
30630
30883
  process.exit(0);
30631
30884
  }
30632
30885
  if (options.help) {
@@ -30657,4 +30910,4 @@ waitUntilExit().then(() => {
30657
30910
  process.exit(0);
30658
30911
  });
30659
30912
 
30660
- //# debugId=F204A4187B2BDE8664756E2164756E21
30913
+ //# debugId=43BB59ABD8BF8C1564756E2164756E21