opencrowd 0.16.4 → 0.16.5
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/bundle/opencrowd.js +98 -24
- package/package.json +1 -1
package/bundle/opencrowd.js
CHANGED
|
@@ -262,7 +262,7 @@ var init_paths = __esm({
|
|
|
262
262
|
});
|
|
263
263
|
|
|
264
264
|
// ../../packages/core/dist/artifacts.js
|
|
265
|
-
import { mkdir as mkdir3, readFile as readFile3 } from "node:fs/promises";
|
|
265
|
+
import { mkdir as mkdir3, readFile as readFile3, readdir, stat } from "node:fs/promises";
|
|
266
266
|
import { dirname as dirname4, join as join3, relative as relative2 } from "node:path";
|
|
267
267
|
async function saveArtifact(state, path3, content, metadata) {
|
|
268
268
|
const target = await safeArtifactPath(state, path3);
|
|
@@ -283,20 +283,74 @@ async function readArtifact(state, path3) {
|
|
|
283
283
|
return readFile3(await safeArtifactPath(state, path3), "utf8");
|
|
284
284
|
}
|
|
285
285
|
async function listArtifacts(state, prefix = "") {
|
|
286
|
-
const { readdir: readdir3 } = await import("node:fs/promises");
|
|
287
286
|
const start = await safeArtifactPath(state, prefix || ".");
|
|
288
287
|
const files = [];
|
|
289
|
-
await
|
|
288
|
+
await walkFiles(start, state.artifactsDir, files);
|
|
290
289
|
return files.sort();
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
290
|
+
}
|
|
291
|
+
async function listOtherChatArtifacts(state) {
|
|
292
|
+
const sessionsDir = dirname4(state.sessionDir);
|
|
293
|
+
let entries;
|
|
294
|
+
try {
|
|
295
|
+
entries = await readdir(sessionsDir, { withFileTypes: true });
|
|
296
|
+
} catch {
|
|
297
|
+
return { chats: [], truncated: false };
|
|
298
|
+
}
|
|
299
|
+
const others = [];
|
|
300
|
+
for (const entry of entries) {
|
|
301
|
+
if (!entry.isDirectory() || entry.name === state.sessionId)
|
|
302
|
+
continue;
|
|
303
|
+
try {
|
|
304
|
+
assertPathId(entry.name);
|
|
305
|
+
} catch {
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
const dir = join3(sessionsDir, entry.name, "artifacts");
|
|
309
|
+
try {
|
|
310
|
+
const info = await stat(join3(sessionsDir, entry.name));
|
|
311
|
+
others.push({ id: entry.name, dir, mtime: info.mtimeMs });
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
others.sort((a, b) => b.mtime - a.mtime);
|
|
316
|
+
const chats = [];
|
|
317
|
+
let remaining = OTHER_CHAT_FILE_LIMIT, truncated = false;
|
|
318
|
+
for (const other of others) {
|
|
319
|
+
if (remaining <= 0) {
|
|
320
|
+
truncated = true;
|
|
321
|
+
break;
|
|
299
322
|
}
|
|
323
|
+
let root;
|
|
324
|
+
try {
|
|
325
|
+
root = await containedPath(sessionsDir, join3(other.id, "artifacts"));
|
|
326
|
+
} catch {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const files = [];
|
|
330
|
+
try {
|
|
331
|
+
await walkFiles(root, root, files);
|
|
332
|
+
} catch {
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
if (!files.length)
|
|
336
|
+
continue;
|
|
337
|
+
files.sort();
|
|
338
|
+
if (files.length > remaining) {
|
|
339
|
+
truncated = true;
|
|
340
|
+
files.length = remaining;
|
|
341
|
+
}
|
|
342
|
+
remaining -= files.length;
|
|
343
|
+
chats.push({ session_id: other.id, shell_dir: `../${other.id}/artifacts`, files });
|
|
344
|
+
}
|
|
345
|
+
return { chats, truncated };
|
|
346
|
+
}
|
|
347
|
+
async function walkFiles(dir, root, out) {
|
|
348
|
+
for (const entry of await readdir(dir, { withFileTypes: true })) {
|
|
349
|
+
const full = join3(dir, entry.name);
|
|
350
|
+
if (entry.isDirectory())
|
|
351
|
+
await walkFiles(full, root, out);
|
|
352
|
+
else if (entry.isFile())
|
|
353
|
+
out.push(relative2(root, full));
|
|
300
354
|
}
|
|
301
355
|
}
|
|
302
356
|
function safeArtifactPath(state, requestedPath) {
|
|
@@ -305,11 +359,13 @@ function safeArtifactPath(state, requestedPath) {
|
|
|
305
359
|
throw new Error(`artifact path: ${error53.message}`);
|
|
306
360
|
});
|
|
307
361
|
}
|
|
362
|
+
var OTHER_CHAT_FILE_LIMIT;
|
|
308
363
|
var init_artifacts = __esm({
|
|
309
364
|
"../../packages/core/dist/artifacts.js"() {
|
|
310
365
|
"use strict";
|
|
311
366
|
init_ledger();
|
|
312
367
|
init_paths();
|
|
368
|
+
OTHER_CHAT_FILE_LIMIT = 300;
|
|
313
369
|
}
|
|
314
370
|
});
|
|
315
371
|
|
|
@@ -17017,7 +17073,7 @@ function toolDescription(name) {
|
|
|
17017
17073
|
case "read_file":
|
|
17018
17074
|
return "Read a session artifact.";
|
|
17019
17075
|
case "list_files":
|
|
17020
|
-
return
|
|
17076
|
+
return `List this chat's artifacts. Each chat with the owner has its own artifacts/ directory, but the owner's Files view shows every chat's files together: set scope="all" to also list files from your other chats before you say a file the owner mentions does not exist.`;
|
|
17021
17077
|
case "run_shell":
|
|
17022
17078
|
return "Run a gated local shell command only when shell access is enabled for the session.";
|
|
17023
17079
|
case "spawn_subagent":
|
|
@@ -17041,7 +17097,10 @@ function toolParameters(name) {
|
|
|
17041
17097
|
case "get_budget_status":
|
|
17042
17098
|
return objectSchema({});
|
|
17043
17099
|
case "list_files":
|
|
17044
|
-
return objectSchema({
|
|
17100
|
+
return objectSchema({
|
|
17101
|
+
prefix: stringSchema("Optional artifact path prefix (this chat only)."),
|
|
17102
|
+
scope: { type: "string", enum: ["chat", "all"], description: "chat (default): this chat's artifacts. all: also every other chat's files, each with the shell_dir to reach it from run_shell." }
|
|
17103
|
+
});
|
|
17045
17104
|
case "save_file":
|
|
17046
17105
|
return objectSchema({
|
|
17047
17106
|
path: stringSchema("Relative artifact path."),
|
|
@@ -17239,8 +17298,21 @@ async function executeTool(name, args, context) {
|
|
|
17239
17298
|
return ok(await saveArtifact(context.session, requiredString(args.path, "path"), requiredString(args.content, "content"), objectValue(args.metadata)));
|
|
17240
17299
|
case "read_file":
|
|
17241
17300
|
return ok({ content: await readArtifact(context.session, requiredString(args.path, "path")) });
|
|
17242
|
-
case "list_files":
|
|
17243
|
-
|
|
17301
|
+
case "list_files": {
|
|
17302
|
+
const files = await listArtifacts(context.session, optionalString(args.prefix, "prefix") ?? "");
|
|
17303
|
+
const scope = optionalString(args.scope, "scope") ?? "chat";
|
|
17304
|
+
if (scope !== "chat" && scope !== "all")
|
|
17305
|
+
throw new Error("scope must be chat or all");
|
|
17306
|
+
if (scope === "chat")
|
|
17307
|
+
return ok(files);
|
|
17308
|
+
const other = await listOtherChatArtifacts(context.session);
|
|
17309
|
+
return ok({
|
|
17310
|
+
files,
|
|
17311
|
+
other_chats: other.chats,
|
|
17312
|
+
...other.truncated ? { truncated: true } : {},
|
|
17313
|
+
note: other.chats.length ? "Files from other chats are already the owner's and already in their Files view. Read one with run_shell at <shell_dir>/<file> (run_shell starts in this chat's session directory). To attach or upload one from this chat, copy it into artifacts/ first; never re-buy or regenerate a file you already hold." : "No other chat of this agent has files."
|
|
17314
|
+
});
|
|
17315
|
+
}
|
|
17244
17316
|
case "run_shell": {
|
|
17245
17317
|
context.onProgress?.({ type: "running_shell", message: "Running gated shell command" });
|
|
17246
17318
|
const result = await runShell(context.session, requiredString(args.command, "command"), optionalString(args.cwd, "cwd") ?? context.session.sessionDir, shellTimeoutMs(args.timeout_ms), { signal: context.signal });
|
|
@@ -89181,8 +89253,10 @@ function createMockToolExecutor() {
|
|
|
89181
89253
|
});
|
|
89182
89254
|
case "read_file":
|
|
89183
89255
|
return ok3({ content: `Mock file content for ${stringValue6(args.path) ?? "unknown path"}.` });
|
|
89184
|
-
case "list_files":
|
|
89185
|
-
|
|
89256
|
+
case "list_files": {
|
|
89257
|
+
const files = ["mock-output.txt"].filter((path3) => path3.startsWith(stringValue6(args.prefix) ?? ""));
|
|
89258
|
+
return ok3(args.scope === "all" ? { files, other_chats: [], note: "No other chat of this agent has files." } : files);
|
|
89259
|
+
}
|
|
89186
89260
|
case "run_shell":
|
|
89187
89261
|
context.onProgress?.({ type: "running_shell", message: "Mock running gated shell command" });
|
|
89188
89262
|
return ok3({
|
|
@@ -89358,7 +89432,7 @@ async function runAgentTaskDetailed(session, task, options = {}) {
|
|
|
89358
89432
|
if (options.hosted)
|
|
89359
89433
|
systemPromptParts.push("You operate this service for its owner. Inference and paid tools debit its USDC wallet. When authorized to build or sell a service, take concrete steps within the owner's configured scope and budget. Ask only for missing information or permissions that materially block progress. Report actual costs and outcomes. Financial sustainability is the owner's business objective; respect their stop controls.", "You are a continuous autonomous agent, not a turn-based assistant. Maintain unfinished goals, promised follow-ups, recurring work, and conditions worth monitoring. When future work would clearly help, proactively create a persistent automation instead of waiting for the owner to say schedule. Use a one-time automation for a future reminder or follow-up and a cron automation for monitoring, recurring reports, or maintenance. It runs in this same conversation. Never create duplicates or noisy schedules, and always tell the owner exactly what you created, its timezone, and next run.", "Before finishing a substantive task, consider whether a follow-up, reminder, monitoring loop, recurring report, or maintenance check would materially advance the owner's goal; create one when the need is clear, but do not schedule ordinary one-off work.", "Financial state: the current hosted financial snapshot is authoritative. It arrives as budget_after_tool_call in the latest tool result or, when no tool has just run, as an automatic CrowdCode note at the start of the latest user message; that note is context, not something the user said, so never reply to it or mention it unless the user asks about money. Historical local session budget figures are not wallet balances and may omit inference spending. Wallet balance, pending payment holds, settled inference spend, settled service spend, and remaining run budget are separate. When the snapshot lists wallet networks, each network's balance is separate: a payment on a network needs that network's available balance. Report the wallet to the owner as one total, mentioning the per-network split only when it matters. Spending totals cover only the identified current run. A budget limit does not supply funds. An unavailable balance is unknown, not zero. The snapshot before a model call excludes that call's eventual charge; never claim a response was free or that you spent nothing merely because no paid tool ran. Use get_budget_status or get_wallet_status for refreshed financial state. Respect approval mode and per-call limits; over-limit requests require the owner's approval.");
|
|
89360
89434
|
if (options.hosted)
|
|
89361
|
-
systemPromptParts.push("Files the owner sends you: an attached file is saved in this session under uploads/ before its message reaches you, and the message names each one with its path, size and type. Read a text file with read_file at uploads/<name>, and any file with run_shell at artifacts/uploads/<name> from the session directory. Those files are already the owner's and already in their file list: work from them, and never copy or re-save one under artifacts/ to hand it back. Write your own outputs elsewhere under artifacts/; uploads/ is the owner's directory and nothing you write there is delivered. If a file the message names is missing, say so and ask the owner to send it again rather than guessing at its contents.", "Files you produce: only the artifacts/ directory of this session reaches the owner. save_file writes there; anything you write elsewhere is scratch they never see. The owner sees each file at its path without that prefix, so artifacts/generated/report.pdf is generated/report.pdf to them. Name a produced file in your final message by exactly that path as plain text and nothing else \u2014 the owner's interface turns it into a working download and preview link. Never invent a download URL, a sandbox: link, a /mnt/data path, or any other path the owner cannot open, and never claim a file exists before you have verified it.");
|
|
89435
|
+
systemPromptParts.push("Files the owner sends you: an attached file is saved in this session under uploads/ before its message reaches you, and the message names each one with its path, size and type. Read a text file with read_file at uploads/<name>, and any file with run_shell at artifacts/uploads/<name> from the session directory. Those files are already the owner's and already in their file list: work from them, and never copy or re-save one under artifacts/ to hand it back. Write your own outputs elsewhere under artifacts/; uploads/ is the owner's directory and nothing you write there is delivered. If a file the message names is missing, say so and ask the owner to send it again rather than guessing at its contents.", "Files you produce: only the artifacts/ directory of this session reaches the owner. save_file writes there; anything you write elsewhere is scratch they never see. The owner sees each file at its path without that prefix, so artifacts/generated/report.pdf is generated/report.pdf to them. Name a produced file in your final message by exactly that path as plain text and nothing else \u2014 the owner's interface turns it into a working download and preview link. Never invent a download URL, a sandbox: link, a /mnt/data path, or any other path the owner cannot open, and never claim a file exists before you have verified it.", `Files from your other chats: each chat with the owner is its own session with its own artifacts/, so list_files and read_file see only this one, while the owner's Files view shows every chat's files together. When the owner mentions a file, PDF or report you do not see here, call list_files with scope="all" before you say it does not exist; it lists each other chat's files with the shell_dir that run_shell reaches them at.`);
|
|
89362
89436
|
if (options.dynamicTools) {
|
|
89363
89437
|
systemPromptParts.push("When the local computer is not the right environment, or after one clear local capability failure, buy external capability: find_paid_service to discover, inspect_paid_service to see the exact schema/price/reputation, call_paid_service to execute through the enforced purchase lifecycle, and review_paid_service for the required review after every confirmed paid call (success or failure). The same review tool accepts unpaid experiences; review relevant free results or failed attempts without inventing payment evidence. Distinguish provider faults from local errors and uncertain failures: a call that never reached the seller is never the seller's fault. funding_required means your USDC is on the wrong network, a cap or a declined approval means the owner's policy stopped you, and an unpayable rail means you could not pay at all \u2014 in every one of those the service was never asked, so it gets no review and certainly not a low rating. Fix the cause and call it again instead; the gateway refuses those reviews, and trying anyway wastes a turn. A platform judge, not you, writes the public score and text of a paid review from the platform's record of the call; your rating and notes are evidence it reads, so report accurately and never try to talk it into a rating.", `Choosing a service: find_paid_service with a short capability query (for example "web search" or "object storage", not the task's subject) searches every catalog (AgentCash, Coinbase's x402 catalog, the MPP catalog and CrowdCode's reviews) across Base, Solana and Tempo and returns services you can pay, ranked best first by CrowdCode: quality (score and verified reviews), then effective price on the service's best network, including about $0.03 to move USDC between your own networks when that network's balance is short, then your balance there. Prefer the highest-ranked service that fits the task, whatever its network; a better or cheaper service on Solana or Tempo beats a Base default. Each result also lists \`networks\`, the networks it can be paid on; between services that fit the task equally well, one you can pay from a balance you already hold beats one that needs a transfer first, because a move costs about $0.03. When the chosen service is marked transfer_needed, move USDC between your own networks first if you have a tool for that; otherwise tell the user which network needs funds. When the ranking is unavailable, compare candidates yourself with inspect_paid_service (reputation, price and network) against your per-network balances.`, ...options.hosted ? [
|
|
89364
89438
|
"You can use new services without prior CrowdCode reviews. Payable: x402 USDC on Base or Solana and MPP USDC.e on Tempo; the hosted gateway pays the cheapest offered network your balance on that network covers. Other networks, including Monad, are not payable here. Payments stay within the user's configured limits; over-limit quotes request approval. Use read_service for authenticated job polling and never resubmit a pending generation job.",
|
|
@@ -90591,7 +90665,7 @@ var init_dist6 = __esm({
|
|
|
90591
90665
|
});
|
|
90592
90666
|
|
|
90593
90667
|
// src/shared.ts
|
|
90594
|
-
import { readdir } from "node:fs/promises";
|
|
90668
|
+
import { readdir as readdir2 } from "node:fs/promises";
|
|
90595
90669
|
import { join as join24, resolve as resolve5 } from "node:path";
|
|
90596
90670
|
import { stdout as output } from "node:process";
|
|
90597
90671
|
function renderKeyValues(value) {
|
|
@@ -90716,7 +90790,7 @@ function isConsumedOption(args, index2, options) {
|
|
|
90716
90790
|
async function latestSessionId(workspaceRoot) {
|
|
90717
90791
|
const sessionsDir = join24(resolve5(workspaceRoot), "sessions");
|
|
90718
90792
|
try {
|
|
90719
|
-
const entries = await
|
|
90793
|
+
const entries = await readdir2(sessionsDir, { withFileTypes: true });
|
|
90720
90794
|
return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort().at(-1);
|
|
90721
90795
|
} catch (error53) {
|
|
90722
90796
|
if (error53.code === "ENOENT") {
|
|
@@ -91899,7 +91973,7 @@ var init_tasks = __esm({
|
|
|
91899
91973
|
});
|
|
91900
91974
|
|
|
91901
91975
|
// ../../packages/evals/dist/scoring.js
|
|
91902
|
-
import { readFile as readFile21, stat } from "node:fs/promises";
|
|
91976
|
+
import { readFile as readFile21, stat as stat2 } from "node:fs/promises";
|
|
91903
91977
|
import { resolve as resolveDns } from "node:dns/promises";
|
|
91904
91978
|
import { join as join30 } from "node:path";
|
|
91905
91979
|
async function scoreTask(task, finalMessage, context = {}) {
|
|
@@ -91949,7 +92023,7 @@ async function scoreTask(task, finalMessage, context = {}) {
|
|
|
91949
92023
|
const path3 = join30(context.artifactsDir, name);
|
|
91950
92024
|
let size5;
|
|
91951
92025
|
try {
|
|
91952
|
-
size5 = (await
|
|
92026
|
+
size5 = (await stat2(path3)).size;
|
|
91953
92027
|
} catch {
|
|
91954
92028
|
continue;
|
|
91955
92029
|
}
|
|
@@ -92547,7 +92621,7 @@ var init_evidence = __esm({
|
|
|
92547
92621
|
|
|
92548
92622
|
// ../../packages/evals/dist/knowledge.js
|
|
92549
92623
|
import { createHash as createHash8 } from "node:crypto";
|
|
92550
|
-
import { mkdir as mkdir18, readdir as
|
|
92624
|
+
import { mkdir as mkdir18, readdir as readdir3, readFile as readFile23, writeFile as writeFile12 } from "node:fs/promises";
|
|
92551
92625
|
import { dirname as dirname15, join as join32, relative as relative4 } from "node:path";
|
|
92552
92626
|
function approxTokens(text) {
|
|
92553
92627
|
return Math.ceil(text.length / 4);
|
|
@@ -92650,7 +92724,7 @@ async function writeTree(dir, tree, meta4) {
|
|
|
92650
92724
|
async function readTree(dir) {
|
|
92651
92725
|
const tree = {};
|
|
92652
92726
|
const walk4 = async (current) => {
|
|
92653
|
-
for (const entry of await
|
|
92727
|
+
for (const entry of await readdir3(current, { withFileTypes: true })) {
|
|
92654
92728
|
const path3 = join32(current, entry.name);
|
|
92655
92729
|
if (entry.isDirectory()) {
|
|
92656
92730
|
await walk4(path3);
|
package/package.json
CHANGED