@runtypelabs/cli 0.2.0 → 0.2.1
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 +7 -0
- package/dist/index.js +342 -15
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -72,6 +72,13 @@ runtype marathon "Code Builder" -m "Refactor the auth module to use JWT tokens"
|
|
|
72
72
|
runtype marathon agent_abc123 -m "Write integration tests for the API" \
|
|
73
73
|
--max-sessions 10 --max-cost 2.50 --name "api-tests"
|
|
74
74
|
|
|
75
|
+
# Override the agent's configured model
|
|
76
|
+
runtype marathon "Code Builder" -m "Build a calculator" --model claude-sonnet-4-5
|
|
77
|
+
|
|
78
|
+
# Enable sandboxed code execution tooling for the task (QuickJS or Daytona)
|
|
79
|
+
runtype marathon "Code Builder" -m "Compute totals from this dataset" --sandbox quickjs
|
|
80
|
+
runtype marathon "Code Builder" -m "Generate a script and run it" --sandbox daytona
|
|
81
|
+
|
|
75
82
|
# Resume an interrupted task (picks up where it left off)
|
|
76
83
|
runtype marathon "Code Builder" -m "Refactor the auth module to use JWT tokens" \
|
|
77
84
|
--resume --name "auth-refactor" --debug
|
package/dist/index.js
CHANGED
|
@@ -2812,6 +2812,205 @@ function saveState(filePath, state) {
|
|
|
2812
2812
|
fs3.mkdirSync(dir, { recursive: true });
|
|
2813
2813
|
fs3.writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
2814
2814
|
}
|
|
2815
|
+
function isRecord(value) {
|
|
2816
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2817
|
+
}
|
|
2818
|
+
function parseSandboxProvider(value) {
|
|
2819
|
+
if (!value) return void 0;
|
|
2820
|
+
const normalized = value.trim().toLowerCase();
|
|
2821
|
+
if (normalized === "quickjs" || normalized === "daytona") return normalized;
|
|
2822
|
+
return void 0;
|
|
2823
|
+
}
|
|
2824
|
+
function parseSandboxLanguage(provider, value) {
|
|
2825
|
+
if (provider === "quickjs") return "javascript";
|
|
2826
|
+
if (typeof value === "string") {
|
|
2827
|
+
const normalized = value.trim().toLowerCase();
|
|
2828
|
+
if (normalized === "javascript" || normalized === "typescript" || normalized === "python") {
|
|
2829
|
+
return normalized;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
return "javascript";
|
|
2833
|
+
}
|
|
2834
|
+
function parseSandboxTimeout(value, provider) {
|
|
2835
|
+
const fallback = provider === "quickjs" ? 5e3 : 3e4;
|
|
2836
|
+
let numericValue;
|
|
2837
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
2838
|
+
numericValue = value;
|
|
2839
|
+
} else if (typeof value === "string" && value.trim() !== "") {
|
|
2840
|
+
const parsed = Number(value);
|
|
2841
|
+
if (Number.isFinite(parsed)) {
|
|
2842
|
+
numericValue = parsed;
|
|
2843
|
+
}
|
|
2844
|
+
}
|
|
2845
|
+
if (numericValue === void 0) return fallback;
|
|
2846
|
+
return Math.max(1, Math.min(3e4, Math.floor(numericValue)));
|
|
2847
|
+
}
|
|
2848
|
+
function parseDaytonaExecutionResult(value) {
|
|
2849
|
+
if (typeof value !== "string") return value;
|
|
2850
|
+
const trimmed = value.trim();
|
|
2851
|
+
if (!trimmed) return "";
|
|
2852
|
+
try {
|
|
2853
|
+
return JSON.parse(trimmed);
|
|
2854
|
+
} catch {
|
|
2855
|
+
const lines = trimmed.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
2856
|
+
const lastLine = lines[lines.length - 1];
|
|
2857
|
+
if (!lastLine) return value;
|
|
2858
|
+
try {
|
|
2859
|
+
return JSON.parse(lastLine);
|
|
2860
|
+
} catch {
|
|
2861
|
+
return value;
|
|
2862
|
+
}
|
|
2863
|
+
}
|
|
2864
|
+
}
|
|
2865
|
+
function createSandboxInstructions(provider) {
|
|
2866
|
+
if (provider === "quickjs") {
|
|
2867
|
+
return [
|
|
2868
|
+
"--- Sandbox Tooling (QuickJS) ---",
|
|
2869
|
+
"You can execute JavaScript snippets with the local tool `run_sandbox_code`.",
|
|
2870
|
+
"Call shape:",
|
|
2871
|
+
'{ "code": "...", "parameters": { ... }, "timeoutMs": 5000 }',
|
|
2872
|
+
"QuickJS rules:",
|
|
2873
|
+
"1. Use JavaScript only (no TypeScript or Python).",
|
|
2874
|
+
"2. Inputs are passed in the `parameters` object (for example: `const x = parameters.x`).",
|
|
2875
|
+
"3. The snippet is wrapped in a function. Use top-level `return ...` to produce the result.",
|
|
2876
|
+
"4. Return JSON-serializable values (object, array, string, number, boolean, null).",
|
|
2877
|
+
"5. No Node/Bun/Deno APIs, imports/require, process, filesystem, or network calls.",
|
|
2878
|
+
"Example:",
|
|
2879
|
+
"const nums = parameters.nums || []",
|
|
2880
|
+
"const sum = nums.reduce((acc, n) => acc + n, 0)",
|
|
2881
|
+
"return { sum, count: nums.length }"
|
|
2882
|
+
].join("\n");
|
|
2883
|
+
}
|
|
2884
|
+
return [
|
|
2885
|
+
"--- Sandbox Tooling (Daytona) ---",
|
|
2886
|
+
"You can execute code snippets with the local tool `run_sandbox_code`.",
|
|
2887
|
+
"Call shape:",
|
|
2888
|
+
'{ "code": "...", "parameters": { ... }, "language": "javascript|typescript|python", "timeoutMs": 30000 }',
|
|
2889
|
+
"Daytona rules:",
|
|
2890
|
+
"1. Choose one language: javascript, typescript, or python.",
|
|
2891
|
+
"2. Parameters are injected as top-level variables before your code (do not rely on `parameters`).",
|
|
2892
|
+
"3. Your snippet runs as a full program. Do not use top-level `return`.",
|
|
2893
|
+
"4. For structured results, write a single JSON value to stdout as the final output.",
|
|
2894
|
+
"5. JS/TS: `console.log(JSON.stringify({ ... }))`; Python: `import json` then `print(json.dumps({ ... }))`.",
|
|
2895
|
+
"6. Avoid extra logs before the final JSON line, or parsing may fail."
|
|
2896
|
+
].join("\n");
|
|
2897
|
+
}
|
|
2898
|
+
function buildResumeCommand(agent, message, options, parsedSandbox) {
|
|
2899
|
+
const nameFlag = options.name ? ` --name ${options.name}` : "";
|
|
2900
|
+
const sandboxFlag = parsedSandbox ? ` --sandbox ${parsedSandbox}` : "";
|
|
2901
|
+
return `runtype marathon ${agent} -m "${message}" --resume${nameFlag}${sandboxFlag}`;
|
|
2902
|
+
}
|
|
2903
|
+
function createSandboxLocalTool(client, provider, debugMode) {
|
|
2904
|
+
return {
|
|
2905
|
+
description: provider === "quickjs" ? "Execute JavaScript code in QuickJS sandbox. Inputs are passed via parameters object." : "Execute JavaScript/TypeScript/Python code in Daytona sandbox. Inputs are injected as top-level variables.",
|
|
2906
|
+
parametersSchema: {
|
|
2907
|
+
type: "object",
|
|
2908
|
+
properties: {
|
|
2909
|
+
code: { type: "string", description: "Code snippet to execute" },
|
|
2910
|
+
parameters: {
|
|
2911
|
+
type: "object",
|
|
2912
|
+
description: "Input parameters for the code (JSON object)"
|
|
2913
|
+
},
|
|
2914
|
+
language: {
|
|
2915
|
+
type: "string",
|
|
2916
|
+
enum: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
|
|
2917
|
+
description: provider === "quickjs" ? "QuickJS only accepts javascript" : "Daytona code language"
|
|
2918
|
+
},
|
|
2919
|
+
timeoutMs: { type: "number", description: "Execution timeout in ms (max 30000)" }
|
|
2920
|
+
},
|
|
2921
|
+
required: ["code"]
|
|
2922
|
+
},
|
|
2923
|
+
execute: async (args) => {
|
|
2924
|
+
const rawCode = args.code;
|
|
2925
|
+
const code = typeof rawCode === "string" ? rawCode : "";
|
|
2926
|
+
if (!code.trim()) {
|
|
2927
|
+
return { success: false, error: "code is required" };
|
|
2928
|
+
}
|
|
2929
|
+
const language = parseSandboxLanguage(provider, args.language);
|
|
2930
|
+
const timeout = parseSandboxTimeout(args.timeoutMs, provider);
|
|
2931
|
+
const parameters = isRecord(args.parameters) ? args.parameters : {};
|
|
2932
|
+
const gateDecision = (0, import_sdk5.evaluateGeneratedRuntimeToolProposal)(
|
|
2933
|
+
{
|
|
2934
|
+
name: "run_sandbox_code",
|
|
2935
|
+
description: `Execute code in ${provider}`,
|
|
2936
|
+
toolType: "custom",
|
|
2937
|
+
parametersSchema: { type: "object" },
|
|
2938
|
+
config: {
|
|
2939
|
+
code,
|
|
2940
|
+
timeout,
|
|
2941
|
+
sandboxProvider: provider,
|
|
2942
|
+
language
|
|
2943
|
+
}
|
|
2944
|
+
},
|
|
2945
|
+
{
|
|
2946
|
+
allowedToolTypes: ["custom"],
|
|
2947
|
+
allowedSandboxProviders: [provider],
|
|
2948
|
+
allowedLanguages: provider === "quickjs" ? ["javascript"] : ["javascript", "typescript", "python"],
|
|
2949
|
+
maxTimeoutMs: 3e4,
|
|
2950
|
+
maxCodeLength: 12e3
|
|
2951
|
+
}
|
|
2952
|
+
);
|
|
2953
|
+
if (!gateDecision.approved) {
|
|
2954
|
+
return {
|
|
2955
|
+
success: false,
|
|
2956
|
+
error: gateDecision.reason,
|
|
2957
|
+
violations: gateDecision.violations
|
|
2958
|
+
};
|
|
2959
|
+
}
|
|
2960
|
+
const tempToolName = `marathon_${provider}_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
|
|
2961
|
+
let tempToolId;
|
|
2962
|
+
try {
|
|
2963
|
+
const createRequest = {
|
|
2964
|
+
name: tempToolName,
|
|
2965
|
+
description: `Ephemeral ${provider} sandbox execution`,
|
|
2966
|
+
toolType: "custom",
|
|
2967
|
+
parametersSchema: { type: "object", properties: {} },
|
|
2968
|
+
config: {
|
|
2969
|
+
code,
|
|
2970
|
+
timeout,
|
|
2971
|
+
allowedApis: [],
|
|
2972
|
+
sandboxProvider: provider,
|
|
2973
|
+
language
|
|
2974
|
+
}
|
|
2975
|
+
};
|
|
2976
|
+
const created = await client.tools.create(createRequest);
|
|
2977
|
+
tempToolId = created.id;
|
|
2978
|
+
const executeRequest = {
|
|
2979
|
+
toolId: created.id,
|
|
2980
|
+
parameters
|
|
2981
|
+
};
|
|
2982
|
+
const execution = await client.tools.execute(created.id, executeRequest);
|
|
2983
|
+
const parsedResult = provider === "daytona" ? parseDaytonaExecutionResult(execution.result) : execution.result;
|
|
2984
|
+
return {
|
|
2985
|
+
success: execution.status === "success",
|
|
2986
|
+
sandboxProvider: provider,
|
|
2987
|
+
language,
|
|
2988
|
+
result: parsedResult,
|
|
2989
|
+
executionId: execution.executionId,
|
|
2990
|
+
...execution.errorMessage ? { error: execution.errorMessage } : {}
|
|
2991
|
+
};
|
|
2992
|
+
} catch (error) {
|
|
2993
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2994
|
+
if (debugMode) {
|
|
2995
|
+
console.log(import_chalk15.default.gray(` [sandbox:${provider}] execution error: ${message}`));
|
|
2996
|
+
}
|
|
2997
|
+
return {
|
|
2998
|
+
success: false,
|
|
2999
|
+
sandboxProvider: provider,
|
|
3000
|
+
language,
|
|
3001
|
+
error: message
|
|
3002
|
+
};
|
|
3003
|
+
} finally {
|
|
3004
|
+
if (tempToolId) {
|
|
3005
|
+
try {
|
|
3006
|
+
await client.tools.delete(tempToolId);
|
|
3007
|
+
} catch {
|
|
3008
|
+
}
|
|
3009
|
+
}
|
|
3010
|
+
}
|
|
3011
|
+
}
|
|
3012
|
+
};
|
|
3013
|
+
}
|
|
2815
3014
|
async function taskAction(agent, options) {
|
|
2816
3015
|
const apiKey = await ensureAuth();
|
|
2817
3016
|
if (!apiKey) return;
|
|
@@ -2819,6 +3018,11 @@ async function taskAction(agent, options) {
|
|
|
2819
3018
|
apiKey,
|
|
2820
3019
|
baseUrl: getApiUrl()
|
|
2821
3020
|
});
|
|
3021
|
+
const parsedSandbox = parseSandboxProvider(options.sandbox);
|
|
3022
|
+
if (options.sandbox && !parsedSandbox) {
|
|
3023
|
+
console.error(import_chalk15.default.red(`Invalid --sandbox value "${options.sandbox}". Use: quickjs or daytona`));
|
|
3024
|
+
process.exit(1);
|
|
3025
|
+
}
|
|
2822
3026
|
let agentId = agent;
|
|
2823
3027
|
if (!agent.startsWith("agent_")) {
|
|
2824
3028
|
const spinner = (0, import_ora10.default)("Looking up agent by name...").start();
|
|
@@ -2831,13 +3035,21 @@ async function taskAction(agent, options) {
|
|
|
2831
3035
|
agentId = found.id;
|
|
2832
3036
|
spinner.succeed(`Found agent: ${import_chalk15.default.green(agentId)}`);
|
|
2833
3037
|
} else {
|
|
2834
|
-
spinner.
|
|
2835
|
-
|
|
2836
|
-
|
|
3038
|
+
spinner.text = `Creating agent "${agent}"...`;
|
|
3039
|
+
try {
|
|
3040
|
+
const created = await client.agents.create({ name: agent });
|
|
3041
|
+
agentId = created.id;
|
|
3042
|
+
spinner.succeed(`Created agent: ${import_chalk15.default.green(agentId)}`);
|
|
3043
|
+
} catch (createErr) {
|
|
3044
|
+
spinner.fail(`Failed to create agent "${agent}"`);
|
|
3045
|
+
const errMsg = createErr instanceof Error ? createErr.message : String(createErr);
|
|
3046
|
+
console.error(import_chalk15.default.red(errMsg));
|
|
3047
|
+
process.exit(1);
|
|
3048
|
+
}
|
|
2837
3049
|
}
|
|
2838
3050
|
} catch (error) {
|
|
2839
|
-
spinner.fail("Failed to
|
|
2840
|
-
const errMsg = error instanceof Error ? error.message :
|
|
3051
|
+
spinner.fail("Failed to list agents");
|
|
3052
|
+
const errMsg = error instanceof Error ? error.message : String(error);
|
|
2841
3053
|
console.error(import_chalk15.default.red(errMsg));
|
|
2842
3054
|
process.exit(1);
|
|
2843
3055
|
}
|
|
@@ -2881,7 +3093,7 @@ async function taskAction(agent, options) {
|
|
|
2881
3093
|
}
|
|
2882
3094
|
console.log(
|
|
2883
3095
|
import_chalk15.default.gray(
|
|
2884
|
-
` Resume with:
|
|
3096
|
+
` Resume with: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
|
|
2885
3097
|
)
|
|
2886
3098
|
);
|
|
2887
3099
|
process.exit(0);
|
|
@@ -2889,32 +3101,63 @@ async function taskAction(agent, options) {
|
|
|
2889
3101
|
process.on("SIGINT", onSigint);
|
|
2890
3102
|
const remainingSessions = maxSessions - priorSessionCount;
|
|
2891
3103
|
const remainingCost = maxCost ? maxCost - priorCost : void 0;
|
|
3104
|
+
const sandboxPrompt = parsedSandbox ? createSandboxInstructions(parsedSandbox) : "";
|
|
3105
|
+
const taskMessage = sandboxPrompt ? `${options.message}
|
|
3106
|
+
|
|
3107
|
+
${sandboxPrompt}` : options.message;
|
|
2892
3108
|
console.log(import_chalk15.default.cyan(`
|
|
2893
3109
|
Running task "${taskName}" on ${agentId}`));
|
|
2894
3110
|
console.log(
|
|
2895
3111
|
import_chalk15.default.gray(
|
|
2896
|
-
` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}`
|
|
3112
|
+
` Sessions: ${priorSessionCount > 0 ? `${priorSessionCount} done, ` : ""}${remainingSessions} remaining${maxCost ? ` | Budget: $${maxCost.toFixed(2)}` : ""}${options.model ? ` | Model: ${options.model}` : ""}${parsedSandbox ? ` | Sandbox: ${parsedSandbox}` : ""}`
|
|
2897
3113
|
)
|
|
2898
3114
|
);
|
|
2899
3115
|
console.log(import_chalk15.default.gray(` State: ${filePath}
|
|
2900
3116
|
`));
|
|
2901
3117
|
try {
|
|
2902
3118
|
let currentSession = priorSessionCount;
|
|
3119
|
+
let thinkingSpinner = null;
|
|
3120
|
+
let thinkingChars = 0;
|
|
2903
3121
|
const streamCallbacks = {
|
|
2904
3122
|
onAgentStart: () => {
|
|
2905
3123
|
currentSession++;
|
|
2906
3124
|
console.log(import_chalk15.default.cyan(`
|
|
2907
3125
|
\u2500\u2500 Session ${currentSession} \u2500\u2500
|
|
2908
3126
|
`));
|
|
3127
|
+
thinkingChars = 0;
|
|
3128
|
+
thinkingSpinner = (0, import_ora10.default)({ text: import_chalk15.default.dim("Thinking..."), color: "gray" }).start();
|
|
2909
3129
|
},
|
|
2910
3130
|
onTurnDelta: (event) => {
|
|
2911
3131
|
if (event.contentType === "text") {
|
|
3132
|
+
if (thinkingSpinner) {
|
|
3133
|
+
thinkingSpinner.stop();
|
|
3134
|
+
thinkingSpinner = null;
|
|
3135
|
+
}
|
|
2912
3136
|
process.stdout.write(event.delta);
|
|
2913
|
-
} else if (event.contentType === "thinking"
|
|
2914
|
-
|
|
3137
|
+
} else if (event.contentType === "thinking") {
|
|
3138
|
+
thinkingChars += event.delta.length;
|
|
3139
|
+
const approxTokens = Math.round(thinkingChars / 4);
|
|
3140
|
+
const tokenStr = approxTokens.toLocaleString();
|
|
3141
|
+
if (!thinkingSpinner) {
|
|
3142
|
+
thinkingSpinner = (0, import_ora10.default)({
|
|
3143
|
+
text: import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`),
|
|
3144
|
+
color: "gray"
|
|
3145
|
+
}).start();
|
|
3146
|
+
} else {
|
|
3147
|
+
thinkingSpinner.text = import_chalk15.default.dim(`Thinking... (~${tokenStr} tokens)`);
|
|
3148
|
+
}
|
|
3149
|
+
if (options.debug) {
|
|
3150
|
+
thinkingSpinner.stop();
|
|
3151
|
+
process.stdout.write(import_chalk15.default.dim(event.delta));
|
|
3152
|
+
thinkingSpinner.start();
|
|
3153
|
+
}
|
|
2915
3154
|
}
|
|
2916
3155
|
},
|
|
2917
3156
|
onToolStart: (event) => {
|
|
3157
|
+
if (thinkingSpinner) {
|
|
3158
|
+
thinkingSpinner.stop();
|
|
3159
|
+
thinkingSpinner = null;
|
|
3160
|
+
}
|
|
2918
3161
|
if (options.debug) {
|
|
2919
3162
|
console.log(import_chalk15.default.gray(`
|
|
2920
3163
|
[tool] ${event.toolName}...`));
|
|
@@ -2926,18 +3169,100 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2926
3169
|
console.log(import_chalk15.default.gray(` [tool] ${event.toolName} \u2192 ${status}`));
|
|
2927
3170
|
}
|
|
2928
3171
|
},
|
|
3172
|
+
onAgentPaused: (event) => {
|
|
3173
|
+
if (thinkingSpinner) {
|
|
3174
|
+
thinkingSpinner.stop();
|
|
3175
|
+
thinkingSpinner = null;
|
|
3176
|
+
}
|
|
3177
|
+
const rawParams = event.parameters;
|
|
3178
|
+
const paramPreview = typeof rawParams === "string" ? `string(${rawParams.length} chars)` : rawParams && typeof rawParams === "object" ? `object(${Object.keys(rawParams).join(", ")})` : typeof rawParams;
|
|
3179
|
+
console.log(
|
|
3180
|
+
import_chalk15.default.cyan(
|
|
3181
|
+
`
|
|
3182
|
+
[local tool] ${event.toolName} called (params: ${paramPreview})`
|
|
3183
|
+
)
|
|
3184
|
+
);
|
|
3185
|
+
if (options.debug) {
|
|
3186
|
+
console.log(import_chalk15.default.gray(` executionId: ${event.executionId}`));
|
|
3187
|
+
console.log(import_chalk15.default.gray(` raw params: ${JSON.stringify(event.parameters).slice(0, 300)}`));
|
|
3188
|
+
}
|
|
3189
|
+
},
|
|
2929
3190
|
onError: (event) => {
|
|
3191
|
+
if (thinkingSpinner) {
|
|
3192
|
+
thinkingSpinner.stop();
|
|
3193
|
+
thinkingSpinner = null;
|
|
3194
|
+
}
|
|
2930
3195
|
console.error(import_chalk15.default.red(`
|
|
2931
3196
|
Error: ${event.error}`));
|
|
2932
3197
|
}
|
|
2933
3198
|
};
|
|
3199
|
+
const defaultLocalTools = {
|
|
3200
|
+
read_file: {
|
|
3201
|
+
description: "Read the contents of a file at the given path",
|
|
3202
|
+
parametersSchema: {
|
|
3203
|
+
type: "object",
|
|
3204
|
+
properties: { path: { type: "string", description: "File path to read" } },
|
|
3205
|
+
required: ["path"]
|
|
3206
|
+
},
|
|
3207
|
+
execute: async (args) => {
|
|
3208
|
+
const filePath2 = String(args.path || "");
|
|
3209
|
+
if (!filePath2) return "Error: path is required";
|
|
3210
|
+
return fs3.readFileSync(filePath2, "utf-8");
|
|
3211
|
+
}
|
|
3212
|
+
},
|
|
3213
|
+
write_file: {
|
|
3214
|
+
description: "Write content to a file, creating directories as needed",
|
|
3215
|
+
parametersSchema: {
|
|
3216
|
+
type: "object",
|
|
3217
|
+
properties: {
|
|
3218
|
+
path: { type: "string", description: "File path to write" },
|
|
3219
|
+
content: { type: "string", description: "Content to write" }
|
|
3220
|
+
},
|
|
3221
|
+
required: ["path", "content"]
|
|
3222
|
+
},
|
|
3223
|
+
execute: async (args) => {
|
|
3224
|
+
const filePath2 = String(args.path || "");
|
|
3225
|
+
if (!filePath2) return "Error: path is required";
|
|
3226
|
+
const content = String(args.content || "");
|
|
3227
|
+
const dir = path4.dirname(filePath2);
|
|
3228
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
3229
|
+
fs3.writeFileSync(filePath2, content);
|
|
3230
|
+
return "ok";
|
|
3231
|
+
}
|
|
3232
|
+
},
|
|
3233
|
+
list_directory: {
|
|
3234
|
+
description: "List files and directories at the given path",
|
|
3235
|
+
parametersSchema: {
|
|
3236
|
+
type: "object",
|
|
3237
|
+
properties: { path: { type: "string", description: 'Directory path (defaults to ".")' } }
|
|
3238
|
+
},
|
|
3239
|
+
execute: async (args) => {
|
|
3240
|
+
const dirPath = String(args.path || ".");
|
|
3241
|
+
return fs3.readdirSync(dirPath).join("\n");
|
|
3242
|
+
}
|
|
3243
|
+
}
|
|
3244
|
+
};
|
|
3245
|
+
const enabledLocalTools = {};
|
|
3246
|
+
if (!options.noLocalTools) {
|
|
3247
|
+
Object.assign(enabledLocalTools, defaultLocalTools);
|
|
3248
|
+
}
|
|
3249
|
+
if (parsedSandbox) {
|
|
3250
|
+
enabledLocalTools.run_sandbox_code = createSandboxLocalTool(
|
|
3251
|
+
client,
|
|
3252
|
+
parsedSandbox,
|
|
3253
|
+
options.debug
|
|
3254
|
+
);
|
|
3255
|
+
}
|
|
3256
|
+
const localTools = Object.keys(enabledLocalTools).length > 0 ? enabledLocalTools : void 0;
|
|
2934
3257
|
const result = await client.agents.runTask(agentId, {
|
|
2935
|
-
message:
|
|
3258
|
+
message: taskMessage,
|
|
2936
3259
|
maxSessions: remainingSessions,
|
|
2937
3260
|
maxCost: remainingCost,
|
|
3261
|
+
model: options.model,
|
|
2938
3262
|
debugMode: options.debug,
|
|
2939
3263
|
stream: true,
|
|
2940
3264
|
streamCallbacks,
|
|
3265
|
+
localTools,
|
|
2941
3266
|
trackProgress: options.track ? taskName : void 0,
|
|
2942
3267
|
onSession: (state) => {
|
|
2943
3268
|
const adjustedState = {
|
|
@@ -2951,7 +3276,7 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2951
3276
|
if (latest) {
|
|
2952
3277
|
const total = adjustedState.sessionCount;
|
|
2953
3278
|
const costStr = import_chalk15.default.yellow(`$${adjustedState.totalCost.toFixed(4)}`);
|
|
2954
|
-
const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : import_chalk15.default.gray;
|
|
3279
|
+
const reasonColor = latest.stopReason === "complete" ? import_chalk15.default.green : latest.stopReason === "error" ? import_chalk15.default.red : import_chalk15.default.gray;
|
|
2955
3280
|
console.log(
|
|
2956
3281
|
`
|
|
2957
3282
|
${import_chalk15.default.dim(`[${total}/${maxSessions}]`)} ${reasonColor(latest.stopReason)} | total: ${costStr}`
|
|
@@ -2988,7 +3313,7 @@ Running task "${taskName}" on ${agentId}`));
|
|
|
2988
3313
|
console.log(
|
|
2989
3314
|
import_chalk15.default.gray(
|
|
2990
3315
|
`
|
|
2991
|
-
Resume:
|
|
3316
|
+
Resume: ${buildResumeCommand(agent, options.message, options, parsedSandbox)}`
|
|
2992
3317
|
)
|
|
2993
3318
|
);
|
|
2994
3319
|
}
|
|
@@ -3011,7 +3336,7 @@ Task failed: ${errMsg}`));
|
|
|
3011
3336
|
}
|
|
3012
3337
|
}
|
|
3013
3338
|
function applyTaskOptions(cmd) {
|
|
3014
|
-
return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").action(taskAction);
|
|
3339
|
+
return cmd.argument("<agent>", "Agent ID or name").requiredOption("-m, --message <text>", "Task message for the agent").option("--max-sessions <n>", "Maximum sessions", "50").option("--max-cost <n>", "Budget in USD").option("--model <modelId>", "Model ID to use (overrides agent config)").option("--name <name>", "Task name (used for state file, defaults to agent name)").option("--state-dir <path>", "Directory for state files (default: .runtype/tasks/)").option("--resume", "Resume from existing local state").option("--track", "Sync progress to a Runtype record (visible in dashboard)").option("--debug", "Show debug output from each session").option("--json", "Output final result as JSON").option("--sandbox <provider>", "Enable sandbox code execution tool (quickjs or daytona)").option("--no-local-tools", "Disable built-in local tool execution (read_file, write_file, list_directory)").action(taskAction);
|
|
3015
3340
|
}
|
|
3016
3341
|
var taskCommand = applyTaskOptions(
|
|
3017
3342
|
new import_commander11.Command("task").description("Run a multi-session agent task")
|
|
@@ -4095,10 +4420,12 @@ program.addCommand(flowVersionsCommand);
|
|
|
4095
4420
|
program.addCommand(createMarathonCommand());
|
|
4096
4421
|
program.exitOverride();
|
|
4097
4422
|
try {
|
|
4098
|
-
|
|
4423
|
+
const userArgs = process.argv.slice(2);
|
|
4424
|
+
const cleanArgs = userArgs[0] === "--" ? userArgs.slice(1) : userArgs;
|
|
4425
|
+
if (!cleanArgs.length) {
|
|
4099
4426
|
handleNoCommand();
|
|
4100
4427
|
} else {
|
|
4101
|
-
program.parse(
|
|
4428
|
+
program.parse(cleanArgs, { from: "user" });
|
|
4102
4429
|
}
|
|
4103
4430
|
} catch (error) {
|
|
4104
4431
|
const commanderError = error;
|