free-pi-cli 0.4.5 → 0.4.6

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
@@ -27,4 +27,4 @@ if (err) {
27
27
  console.error(err);
28
28
  process.exit(1);
29
29
  }
30
- await import("./main-r61kpjqw.js");
30
+ await import("./main-cksegxnv.js");
@@ -45,7 +45,7 @@ function openBrowser(url, platform = process.platform, spawnImpl = spawn) {
45
45
  // package.json
46
46
  var package_default = {
47
47
  name: "free-pi-cli",
48
- version: "0.4.5",
48
+ version: "0.4.6",
49
49
  description: "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
50
50
  license: "MIT",
51
51
  type: "module",
@@ -5840,6 +5840,9 @@ var F64Out = new Uint8Array(F64.buffer);
5840
5840
  var encoder = new TextEncoder;
5841
5841
  // ../../node_modules/.bun/typebox@1.3.27/node_modules/typebox/build/type/types/integer.mjs
5842
5842
  var IntegerPattern = "-?(?:0|[1-9][0-9]*)";
5843
+ function Integer(options) {
5844
+ return Create({ "~kind": "Integer" }, { type: "integer" }, options);
5845
+ }
5843
5846
  // ../../node_modules/.bun/typebox@1.3.27/node_modules/typebox/build/type/types/literal.mjs
5844
5847
  class InvalidLiteralValue extends Error {
5845
5848
  constructor(value) {
@@ -5970,6 +5973,106 @@ function createUsageToolExtension(opts) {
5970
5973
  };
5971
5974
  }
5972
5975
 
5976
+ // src/web-tools.ts
5977
+ var WEB_SEARCH_TOOL_NAME = "web_search";
5978
+ var DOCS_LOOKUP_TOOL_NAME = "docs_lookup";
5979
+ var COST_GUIDELINE = "Each web_search or docs_lookup call costs part of the user's daily allowance; one or two well-aimed calls usually suffice.";
5980
+ var DOCS_LOOKUP_GUIDELINES = [
5981
+ "Use docs_lookup before writing or fixing code against a third-party library, framework, SDK or API whose exact signature or config you are not sure of, and whenever an import, method or option you used turns out not to exist.",
5982
+ 'Pass the package name as `library` (e.g. "next.js", "prisma", "@tanstack/react-query") and one specific question as `query` (e.g. "configure middleware matcher for API routes"), not a bare topic. Reuse the returned `library_id` for follow-up lookups on the same library.',
5983
+ COST_GUIDELINE
5984
+ ];
5985
+ var WEB_SEARCH_GUIDELINES = [
5986
+ "Use web_search for things that change or are newer than your knowledge: release notes, current versions, exact error messages you cannot explain from the code, service status, and pages the user links or mentions. Prefer docs_lookup for library API docs, and read/grep for anything in the local project.",
5987
+ "Write a specific query the way you would type it into a search engine (include the product name, the version and the exact error text). Read the returned page text before searching again, and do not repeat a query that already returned results. Cite the URLs you relied on in your answer.",
5988
+ COST_GUIDELINE
5989
+ ];
5990
+ var ERROR_TEXT = {
5991
+ daily_cap: "The user's daily free usage is used up. Do not retry; tell the user and continue without this tool.",
5992
+ rolling_cap: "The user's short-term usage limit is reached. Do not retry; continue without this tool.",
5993
+ rate_limited: "Too many calls right now. Wait for the current call to finish, and do not call again in this turn unless needed.",
5994
+ not_found: (library) => `No documentation library matched "${library}". Retry once with the package's exact name, or use web_search.`,
5995
+ not_configured: "This tool is not available on this server. Do not call it again in this session.",
5996
+ upstream_error: "The search provider failed. You may retry once."
5997
+ };
5998
+ async function post(opts, path, body, label, signal) {
5999
+ try {
6000
+ const timeout = AbortSignal.timeout(30000);
6001
+ const res = await (opts.fetchImpl ?? fetch)(`${opts.baseUrl}${path}`, {
6002
+ method: "POST",
6003
+ headers: { Authorization: `Bearer ${await opts.getToken()}`, "Content-Type": "application/json" },
6004
+ body: JSON.stringify(body),
6005
+ signal: signal ? AbortSignal.any([signal, timeout]) : timeout
6006
+ });
6007
+ if (res.ok)
6008
+ return { ok: true, data: await res.json() };
6009
+ const err = await res.json().catch(() => ({}));
6010
+ const mapped = ERROR_TEXT[err.code ?? ""];
6011
+ if (mapped)
6012
+ return { ok: false, text: typeof mapped === "function" ? mapped(label) : mapped };
6013
+ return { ok: false, text: `Request failed (HTTP ${res.status}): ${err.message ?? "no message"}` };
6014
+ } catch (e) {
6015
+ if (e instanceof Error && e.name === "TimeoutError")
6016
+ return { ok: false, text: "Request timed out after 30 seconds." };
6017
+ return { ok: false, text: `Request failed: ${String(e)}` };
6018
+ }
6019
+ }
6020
+ var done = (o) => ({ content: [{ type: "text", text: o.text }], details: o.details });
6021
+ function createWebToolsExtension(opts) {
6022
+ return {
6023
+ name: "free-pi-web-tools",
6024
+ factory(pi) {
6025
+ pi.registerTool({
6026
+ name: WEB_SEARCH_TOOL_NAME,
6027
+ label: "Web Search",
6028
+ description: "Search the web and return a numbered list of results, each with title, URL, publish date and the page text. Use it for current or recent information that your training data may lack. Each call uses part of the user's daily allowance.",
6029
+ promptSnippet: "Search the web for current information (counts against the user's daily allowance)",
6030
+ promptGuidelines: WEB_SEARCH_GUIDELINES,
6031
+ parameters: _Object_({
6032
+ query: String2({ minLength: 1, maxLength: 500, description: 'Specific query as you would type it into a search engine, e.g. "vite 6 release notes breaking changes"' }),
6033
+ num_results: Optional(Integer({ minimum: 1, maximum: 10, description: "1-10, default 5; use 3 for a quick fact, 8-10 for a survey" }))
6034
+ }),
6035
+ async execute(_id, params, signal) {
6036
+ const r = await post(opts, "/tools/web-search", params, "", signal);
6037
+ if (!r.ok)
6038
+ return done({ text: r.text, details: { ok: false } });
6039
+ const results = r.data.results ?? [];
6040
+ const text = results.length ? `Web results for "${params.query}":
6041
+
6042
+ ` + results.map((x, i) => `${i + 1}. ${x.title}
6043
+ ${x.url}${x.published_date ? `
6044
+ Published: ${x.published_date}` : ""}
6045
+ ${x.text}`).join(`
6046
+
6047
+ `) : `No results for "${params.query}". Try a broader or differently worded query.`;
6048
+ return done({ text, details: { ok: true, cost_usd: r.data.cost_usd } });
6049
+ }
6050
+ });
6051
+ pi.registerTool({
6052
+ name: DOCS_LOOKUP_TOOL_NAME,
6053
+ label: "Docs Lookup",
6054
+ description: "Look up current documentation for a third-party library, framework or API. Returns the matching library's title and library_id, then documentation text relevant to your query. Use it instead of relying on memory for exact signatures and options. Each call uses part of the user's daily allowance.",
6055
+ promptSnippet: "Look up library/framework documentation before relying on memory (counts against the user's daily allowance)",
6056
+ promptGuidelines: DOCS_LOOKUP_GUIDELINES,
6057
+ parameters: _Object_({
6058
+ library: String2({ minLength: 1, maxLength: 200, description: 'Package or library name, e.g. "next.js", "prisma", "@tanstack/react-query"' }),
6059
+ query: String2({ minLength: 1, maxLength: 500, description: 'One specific question, e.g. "configure middleware matcher for API routes"' }),
6060
+ library_id: Optional(String2({ description: "The library_id printed by an earlier docs_lookup, e.g. /vercel/next.js; skips the name search" }))
6061
+ }),
6062
+ async execute(_id, params, signal) {
6063
+ const r = await post(opts, "/tools/docs", params, params.library, signal);
6064
+ if (!r.ok)
6065
+ return done({ text: r.text, details: { ok: false } });
6066
+ const d = r.data;
6067
+ return done({ text: `${d.title} (library_id: ${d.library_id})
6068
+
6069
+ ${d.docs}`, details: { ok: true, cost_usd: d.cost_usd } });
6070
+ }
6071
+ });
6072
+ }
6073
+ };
6074
+ }
6075
+
5973
6076
  // src/buy-tool.ts
5974
6077
  async function resolveBuyPage(opts) {
5975
6078
  try {
@@ -6602,6 +6705,12 @@ function installFooterRightAlign(mode) {
6602
6705
 
6603
6706
  // src/changelog.ts
6604
6707
  var CHANGELOG_HIGHLIGHTS = [
6708
+ {
6709
+ version: "0.4.6",
6710
+ highlights: [
6711
+ "Free web search and documentation lookup: the agent can now search the web (web_search) and look up current library docs (docs_lookup). Both run on the free-pi server and count toward your daily allowance."
6712
+ ]
6713
+ },
6605
6714
  {
6606
6715
  version: "0.4.5",
6607
6716
  highlights: [
@@ -7182,6 +7291,8 @@ var ALLOWED_TOOL_NAMES = [
7182
7291
  USAGE_TOOL_NAME,
7183
7292
  BUY_TOOL_NAME,
7184
7293
  DOCS_TOOL_NAME,
7294
+ WEB_SEARCH_TOOL_NAME,
7295
+ DOCS_LOOKUP_TOOL_NAME,
7185
7296
  TODO_TOOL_NAME,
7186
7297
  "codemode",
7187
7298
  "tool_search"
@@ -7240,6 +7351,10 @@ function buildRuntimeOptions(opts, sessionId) {
7240
7351
  getToken: () => opts.jwt
7241
7352
  });
7242
7353
  const docsToolExtension = createDocsToolExtension();
7354
+ const webToolsExtension = createWebToolsExtension({
7355
+ baseUrl: opts.baseUrl,
7356
+ getToken: () => opts.jwt
7357
+ });
7243
7358
  const errorNoticeExtension = createErrorNoticeExtension();
7244
7359
  const toolGuardExtension = createToolGuardExtension({
7245
7360
  baseUrl: opts.baseUrl,
@@ -7267,6 +7382,7 @@ function buildRuntimeOptions(opts, sessionId) {
7267
7382
  usageToolExtension,
7268
7383
  buyToolExtension,
7269
7384
  docsToolExtension,
7385
+ webToolsExtension,
7270
7386
  errorNoticeExtension,
7271
7387
  toolGuardExtension,
7272
7388
  commandsExtension,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "free-pi-cli",
3
- "version": "0.4.5",
3
+ "version": "0.4.6",
4
4
  "description": "Free, ad-supported distribution of the pi coding agent. Inference paid for by ads.",
5
5
  "license": "MIT",
6
6
  "type": "module",