@bunny-agent/runner-cli 0.9.59-beta.7 → 0.9.59
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/bundle.mjs +136 -13
- package/package.json +7 -7
package/dist/bundle.mjs
CHANGED
|
@@ -330,6 +330,16 @@ var createLegacyAgentTurnInput = (userInput) => ({
|
|
|
330
330
|
execution: {}
|
|
331
331
|
});
|
|
332
332
|
|
|
333
|
+
// ../../packages/manager/dist/approval-file.js
|
|
334
|
+
import { createHash } from "node:crypto";
|
|
335
|
+
var LEGACY_APPROVAL_FILE_STEM_MAX_BYTES = 200;
|
|
336
|
+
var SAFE_APPROVAL_FILE_STEM = /^[A-Za-z0-9._-]+$/;
|
|
337
|
+
function approvalFileName(toolCallId) {
|
|
338
|
+
const useLegacyName = SAFE_APPROVAL_FILE_STEM.test(toolCallId) && Buffer.byteLength(toolCallId, "utf8") <= LEGACY_APPROVAL_FILE_STEM_MAX_BYTES;
|
|
339
|
+
const stem = useLegacyName ? toolCallId : `hashed-${createHash("sha256").update(toolCallId).digest("hex")}`;
|
|
340
|
+
return `${stem}.json`;
|
|
341
|
+
}
|
|
342
|
+
|
|
333
343
|
// src/env-payload.ts
|
|
334
344
|
function takeAgentInputFromEnv(env = process.env) {
|
|
335
345
|
const raw = env.BUNNY_AGENT_INPUT_JSON;
|
|
@@ -14716,6 +14726,10 @@ function errorResult(text) {
|
|
|
14716
14726
|
}
|
|
14717
14727
|
|
|
14718
14728
|
// ../../packages/runner-claude/dist/claude-runner.js
|
|
14729
|
+
var DEFAULT_ASK_USER_QUESTION_TIMEOUT_MS = 18e4;
|
|
14730
|
+
var MAX_ASK_USER_QUESTIONS = 8;
|
|
14731
|
+
var ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY = "__bunny_agent_timeout__";
|
|
14732
|
+
var ASK_USER_QUESTION_TIMEOUT_MESSAGE = "The user did not answer before the interactive question timed out. Continue the original task without waiting, using reasonable assumptions when safe, and provide a user-visible response. Do not call AskUserQuestion again during this turn.";
|
|
14719
14733
|
function buildUserMessage(userInput) {
|
|
14720
14734
|
const parsedContent = typeof userInput === "string" ? userInput : buildStructuredClaudeContent(userInput);
|
|
14721
14735
|
return {
|
|
@@ -14749,8 +14763,27 @@ async function* buildSDKUserMessageIterable(userInput) {
|
|
|
14749
14763
|
yield buildUserMessage(userInput);
|
|
14750
14764
|
}
|
|
14751
14765
|
function createCanUseToolCallback(claudeOptions) {
|
|
14766
|
+
let questionTimedOut = false;
|
|
14752
14767
|
return async (toolName, input, options) => {
|
|
14753
14768
|
const { toolUseID } = options;
|
|
14769
|
+
const questions = input?.questions;
|
|
14770
|
+
if (toolName === "AskUserQuestion" && Array.isArray(questions) && questions.length > MAX_ASK_USER_QUESTIONS) {
|
|
14771
|
+
return {
|
|
14772
|
+
behavior: "deny",
|
|
14773
|
+
message: `AskUserQuestion supports at most ${MAX_ASK_USER_QUESTIONS} questions per survey.`
|
|
14774
|
+
};
|
|
14775
|
+
}
|
|
14776
|
+
if (toolName === "AskUserQuestion" && questionTimedOut) {
|
|
14777
|
+
return {
|
|
14778
|
+
behavior: "allow",
|
|
14779
|
+
updatedInput: {
|
|
14780
|
+
questions,
|
|
14781
|
+
answers: {
|
|
14782
|
+
[ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY]: ASK_USER_QUESTION_TIMEOUT_MESSAGE
|
|
14783
|
+
}
|
|
14784
|
+
}
|
|
14785
|
+
};
|
|
14786
|
+
}
|
|
14754
14787
|
if (claudeOptions.yolo && toolName !== "AskUserQuestion") {
|
|
14755
14788
|
return {
|
|
14756
14789
|
behavior: "allow",
|
|
@@ -14762,18 +14795,21 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
14762
14795
|
const fs3 = await import("node:fs");
|
|
14763
14796
|
const path3 = await import("node:path");
|
|
14764
14797
|
const approvalDir = path3.join(cwd, ".bunny-agent", "approvals");
|
|
14765
|
-
const approvalFile = path3.join(approvalDir,
|
|
14798
|
+
const approvalFile = path3.join(approvalDir, approvalFileName(toolUseID));
|
|
14766
14799
|
fs3.mkdirSync(approvalDir, { recursive: true });
|
|
14767
14800
|
if (!fs3.existsSync(approvalFile)) {
|
|
14768
14801
|
fs3.writeFileSync(approvalFile, JSON.stringify({
|
|
14769
14802
|
status: "pending",
|
|
14770
14803
|
toolName,
|
|
14771
14804
|
input,
|
|
14772
|
-
questions: toolName === "AskUserQuestion" ?
|
|
14805
|
+
questions: toolName === "AskUserQuestion" ? questions : void 0,
|
|
14773
14806
|
answers: {}
|
|
14774
14807
|
}));
|
|
14775
14808
|
}
|
|
14776
|
-
|
|
14809
|
+
const timeoutMs = toolName === "AskUserQuestion" ? claudeOptions.askUserQuestionTimeoutMs ?? DEFAULT_ASK_USER_QUESTION_TIMEOUT_MS : Number.POSITIVE_INFINITY;
|
|
14810
|
+
const deadline = Date.now() + Math.max(0, timeoutMs);
|
|
14811
|
+
let lastApproval = null;
|
|
14812
|
+
while (Date.now() < deadline) {
|
|
14777
14813
|
if (options.signal?.aborted) {
|
|
14778
14814
|
try {
|
|
14779
14815
|
fs3.unlinkSync(approvalFile);
|
|
@@ -14787,6 +14823,7 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
14787
14823
|
try {
|
|
14788
14824
|
const data = fs3.readFileSync(approvalFile, "utf-8");
|
|
14789
14825
|
const approval = JSON.parse(data);
|
|
14826
|
+
lastApproval = approval;
|
|
14790
14827
|
if (approval.status === "completed") {
|
|
14791
14828
|
try {
|
|
14792
14829
|
fs3.unlinkSync(approvalFile);
|
|
@@ -14804,6 +14841,21 @@ function createCanUseToolCallback(claudeOptions) {
|
|
|
14804
14841
|
}
|
|
14805
14842
|
await new Promise((resolve5) => setTimeout(resolve5, 500));
|
|
14806
14843
|
}
|
|
14844
|
+
try {
|
|
14845
|
+
fs3.unlinkSync(approvalFile);
|
|
14846
|
+
} catch {
|
|
14847
|
+
}
|
|
14848
|
+
questionTimedOut = true;
|
|
14849
|
+
return {
|
|
14850
|
+
behavior: "allow",
|
|
14851
|
+
updatedInput: {
|
|
14852
|
+
questions: lastApproval?.questions ?? input?.questions,
|
|
14853
|
+
answers: {
|
|
14854
|
+
...lastApproval?.answers ?? {},
|
|
14855
|
+
[ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY]: ASK_USER_QUESTION_TIMEOUT_MESSAGE
|
|
14856
|
+
}
|
|
14857
|
+
}
|
|
14858
|
+
};
|
|
14807
14859
|
} catch (error48) {
|
|
14808
14860
|
console.error("Failed to handle approval flow:", error48);
|
|
14809
14861
|
return {
|
|
@@ -20951,6 +21003,11 @@ function getUsageFromAgentEndMessages(messages) {
|
|
|
20951
21003
|
}
|
|
20952
21004
|
|
|
20953
21005
|
// ../../packages/runner-pi/dist/stream-converter.js
|
|
21006
|
+
var ASK_USER_QUESTION_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
21007
|
+
"AskUserQuestion",
|
|
21008
|
+
"ask_user_question"
|
|
21009
|
+
]);
|
|
21010
|
+
var ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY2 = "__bunny_agent_timeout__";
|
|
20954
21011
|
function emitStreamError(errorText) {
|
|
20955
21012
|
const errorLine = "data: " + JSON.stringify({ type: "error", errorText }) + "\n\n";
|
|
20956
21013
|
const finishLine = "data: " + JSON.stringify({ type: "finish", finishReason: "error" }) + "\n\n";
|
|
@@ -20973,6 +21030,23 @@ function extractToolResultText(result) {
|
|
|
20973
21030
|
return String(result);
|
|
20974
21031
|
}
|
|
20975
21032
|
}
|
|
21033
|
+
function extractAskUserQuestionOutput(toolName, result) {
|
|
21034
|
+
if (!ASK_USER_QUESTION_TOOL_NAMES.has(toolName))
|
|
21035
|
+
return void 0;
|
|
21036
|
+
if (result === null || typeof result !== "object")
|
|
21037
|
+
return void 0;
|
|
21038
|
+
const details = result.details;
|
|
21039
|
+
if (details === null || typeof details !== "object" || Array.isArray(details)) {
|
|
21040
|
+
return void 0;
|
|
21041
|
+
}
|
|
21042
|
+
const answers = details.answers;
|
|
21043
|
+
if (answers === null || typeof answers !== "object" || Array.isArray(answers)) {
|
|
21044
|
+
return void 0;
|
|
21045
|
+
}
|
|
21046
|
+
return {
|
|
21047
|
+
answers: Object.fromEntries(Object.entries(answers).filter(([key]) => key !== ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY2))
|
|
21048
|
+
};
|
|
21049
|
+
}
|
|
20976
21050
|
function sseData4(obj) {
|
|
20977
21051
|
return "data: " + JSON.stringify(obj) + "\n\n";
|
|
20978
21052
|
}
|
|
@@ -21034,7 +21108,7 @@ var PiAISDKStreamConverter = class {
|
|
|
21034
21108
|
return chunks;
|
|
21035
21109
|
}
|
|
21036
21110
|
if (event.type === "tool_execution_end") {
|
|
21037
|
-
const
|
|
21111
|
+
const textOutput = this.options.normalizeToolOutput(event.result);
|
|
21038
21112
|
const raw = event.result?.details?.usage?.raw;
|
|
21039
21113
|
if (raw != null)
|
|
21040
21114
|
accumulateToolUsage(this.toolUsageTally, raw);
|
|
@@ -21042,11 +21116,12 @@ var PiAISDKStreamConverter = class {
|
|
|
21042
21116
|
chunks.push(sseData4({
|
|
21043
21117
|
type: "tool-output-error",
|
|
21044
21118
|
toolCallId: event.toolCallId,
|
|
21045
|
-
errorText:
|
|
21119
|
+
errorText: textOutput,
|
|
21046
21120
|
dynamic: true,
|
|
21047
21121
|
providerExecuted: true
|
|
21048
21122
|
}));
|
|
21049
21123
|
} else {
|
|
21124
|
+
const output = extractAskUserQuestionOutput(event.toolName, event.result) ?? textOutput;
|
|
21050
21125
|
chunks.push(sseData4({
|
|
21051
21126
|
type: "tool-output-available",
|
|
21052
21127
|
toolCallId: event.toolCallId,
|
|
@@ -23755,12 +23830,16 @@ var Type = type_exports2;
|
|
|
23755
23830
|
// ../../packages/runner-pi/dist/tool-approval.js
|
|
23756
23831
|
var ASK_USER_QUESTION_TOOL_NAME = "ask_user_question";
|
|
23757
23832
|
var LEGACY_ASK_USER_QUESTION_TOOL_NAME = "AskUserQuestion";
|
|
23833
|
+
var DEFAULT_ASK_USER_QUESTION_TIMEOUT_MS2 = 18e4;
|
|
23834
|
+
var MAX_ASK_USER_QUESTIONS2 = 8;
|
|
23835
|
+
var ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3 = "__bunny_agent_timeout__";
|
|
23836
|
+
var ASK_USER_QUESTION_TIMEOUT_MESSAGE2 = "The user did not answer before the interactive question timed out. Do not call ask_user_question again during this turn.";
|
|
23758
23837
|
function isAskUserQuestionToolName(toolName) {
|
|
23759
23838
|
return toolName === ASK_USER_QUESTION_TOOL_NAME || toolName === LEGACY_ASK_USER_QUESTION_TOOL_NAME;
|
|
23760
23839
|
}
|
|
23761
23840
|
var DEFAULT_POLL_INTERVAL_MS = 500;
|
|
23762
23841
|
function approvalFilePath(cwd, toolCallId) {
|
|
23763
|
-
return path2.join(cwd, ".bunny-agent", "approvals",
|
|
23842
|
+
return path2.join(cwd, ".bunny-agent", "approvals", approvalFileName(toolCallId));
|
|
23764
23843
|
}
|
|
23765
23844
|
async function waitForApproval(options) {
|
|
23766
23845
|
const { cwd, toolCallId, toolName, input, signal, pollIntervalMs = DEFAULT_POLL_INTERVAL_MS, timeoutMs } = options;
|
|
@@ -23811,12 +23890,15 @@ async function waitForApproval(options) {
|
|
|
23811
23890
|
await sleepWithAbort(pollIntervalMs, signal);
|
|
23812
23891
|
}
|
|
23813
23892
|
cleanup();
|
|
23814
|
-
if (
|
|
23893
|
+
if (isAskUserQuestionToolName(toolName)) {
|
|
23815
23894
|
return {
|
|
23816
23895
|
behavior: "allow",
|
|
23817
23896
|
updatedInput: {
|
|
23818
|
-
questions: lastApproval
|
|
23819
|
-
answers:
|
|
23897
|
+
questions: lastApproval?.questions ?? input?.questions,
|
|
23898
|
+
answers: {
|
|
23899
|
+
...lastApproval?.answers ?? {},
|
|
23900
|
+
[ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3]: ASK_USER_QUESTION_TIMEOUT_MESSAGE2
|
|
23901
|
+
}
|
|
23820
23902
|
}
|
|
23821
23903
|
};
|
|
23822
23904
|
}
|
|
@@ -23854,9 +23936,20 @@ var askUserQuestionParameters = Type.Object({
|
|
|
23854
23936
|
multiSelect: Type.Optional(Type.Boolean({
|
|
23855
23937
|
description: "Allow selecting multiple options."
|
|
23856
23938
|
}))
|
|
23857
|
-
}), {
|
|
23939
|
+
}), {
|
|
23940
|
+
description: `Questions to present to the user (maximum ${MAX_ASK_USER_QUESTIONS2}).`,
|
|
23941
|
+
maxItems: MAX_ASK_USER_QUESTIONS2
|
|
23942
|
+
})
|
|
23858
23943
|
});
|
|
23859
23944
|
function formatAskUserQuestionResult(updatedInput) {
|
|
23945
|
+
if (ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3 in updatedInput.answers) {
|
|
23946
|
+
const availableAnswers = Object.fromEntries(Object.entries(updatedInput.answers).filter(([key]) => key !== ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3));
|
|
23947
|
+
return [
|
|
23948
|
+
ASK_USER_QUESTION_TIMEOUT_MESSAGE2,
|
|
23949
|
+
`Available answers: ${JSON.stringify(availableAnswers)}`,
|
|
23950
|
+
"Continue the original task without waiting. Use any available answers, make reasonable assumptions when safe, and provide a user-visible response. Do not call ask_user_question again during this turn."
|
|
23951
|
+
].join("\n");
|
|
23952
|
+
}
|
|
23860
23953
|
return [
|
|
23861
23954
|
"The user answered the interactive questions.",
|
|
23862
23955
|
`Answers: ${JSON.stringify(updatedInput.answers)}`,
|
|
@@ -23864,12 +23957,34 @@ function formatAskUserQuestionResult(updatedInput) {
|
|
|
23864
23957
|
].join("\n");
|
|
23865
23958
|
}
|
|
23866
23959
|
function buildAskUserQuestionTool(options) {
|
|
23960
|
+
let questionTimedOut = false;
|
|
23867
23961
|
return {
|
|
23868
23962
|
name: ASK_USER_QUESTION_TOOL_NAME,
|
|
23869
23963
|
label: "Ask User Question",
|
|
23870
23964
|
description: "Ask the user one or more questions and wait for their answers. Use this when you need clarification, a decision between options, or missing information required to continue the task.",
|
|
23871
23965
|
parameters: askUserQuestionParameters,
|
|
23872
23966
|
async execute(toolCallId, params, signal) {
|
|
23967
|
+
const questions = params?.questions;
|
|
23968
|
+
if (Array.isArray(questions) && questions.length > MAX_ASK_USER_QUESTIONS2) {
|
|
23969
|
+
throw new Error(`ask_user_question supports at most ${MAX_ASK_USER_QUESTIONS2} questions per survey.`);
|
|
23970
|
+
}
|
|
23971
|
+
if (questionTimedOut) {
|
|
23972
|
+
const updatedInput = {
|
|
23973
|
+
questions,
|
|
23974
|
+
answers: {
|
|
23975
|
+
[ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3]: ASK_USER_QUESTION_TIMEOUT_MESSAGE2
|
|
23976
|
+
}
|
|
23977
|
+
};
|
|
23978
|
+
return {
|
|
23979
|
+
content: [
|
|
23980
|
+
{
|
|
23981
|
+
type: "text",
|
|
23982
|
+
text: formatAskUserQuestionResult(updatedInput)
|
|
23983
|
+
}
|
|
23984
|
+
],
|
|
23985
|
+
details: updatedInput
|
|
23986
|
+
};
|
|
23987
|
+
}
|
|
23873
23988
|
const decision = await waitForApproval({
|
|
23874
23989
|
cwd: options.cwd,
|
|
23875
23990
|
toolCallId,
|
|
@@ -23877,11 +23992,12 @@ function buildAskUserQuestionTool(options) {
|
|
|
23877
23992
|
input: params,
|
|
23878
23993
|
signal: signal ?? options.fallbackSignal,
|
|
23879
23994
|
pollIntervalMs: options.pollIntervalMs,
|
|
23880
|
-
timeoutMs: options.timeoutMs
|
|
23995
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_ASK_USER_QUESTION_TIMEOUT_MS2
|
|
23881
23996
|
});
|
|
23882
23997
|
if (decision.behavior === "deny") {
|
|
23883
23998
|
throw new Error(decision.message);
|
|
23884
23999
|
}
|
|
24000
|
+
questionTimedOut = ASK_USER_QUESTION_TIMEOUT_ANSWER_KEY3 in decision.updatedInput.answers;
|
|
23885
24001
|
return {
|
|
23886
24002
|
content: [
|
|
23887
24003
|
{
|
|
@@ -24836,7 +24952,13 @@ function createPiRunner(options = {}) {
|
|
|
24836
24952
|
resourceLoader,
|
|
24837
24953
|
thinkingLevel: options.effort ? options.effort : void 0,
|
|
24838
24954
|
tools: allowedTools,
|
|
24839
|
-
customTools: [
|
|
24955
|
+
customTools: [
|
|
24956
|
+
...gatedTools,
|
|
24957
|
+
buildAskUserQuestionTool({
|
|
24958
|
+
...approvalGate,
|
|
24959
|
+
timeoutMs: options.askUserQuestionTimeoutMs ?? DEFAULT_ASK_USER_QUESTION_TIMEOUT_MS2
|
|
24960
|
+
})
|
|
24961
|
+
]
|
|
24840
24962
|
});
|
|
24841
24963
|
try {
|
|
24842
24964
|
await session.bindExtensions({ mode: "print" });
|
|
@@ -25028,7 +25150,8 @@ function createRunner(options) {
|
|
|
25028
25150
|
resume,
|
|
25029
25151
|
yolo: options.yolo,
|
|
25030
25152
|
env,
|
|
25031
|
-
abortController
|
|
25153
|
+
abortController,
|
|
25154
|
+
askUserQuestionTimeoutMs: options.askUserQuestionTimeoutMs
|
|
25032
25155
|
};
|
|
25033
25156
|
const input = options.input ? parseAgentTurnInputV1(options.input) : createLegacyAgentTurnInput(options.userInput ?? "");
|
|
25034
25157
|
const rawStream = dispatchRunner(options.runner, base, cwd, options, input);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bunny-agent/runner-cli",
|
|
3
|
-
"version": "0.9.59
|
|
3
|
+
"version": "0.9.59",
|
|
4
4
|
"description": "BunnyAgent Runner CLI - Like gemini-cli or claude-code, runs in your local terminal with AI SDK UI streaming",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -59,15 +59,15 @@
|
|
|
59
59
|
"esbuild": "^0.27.2",
|
|
60
60
|
"typescript": "^5.3.0",
|
|
61
61
|
"vitest": "^1.6.1",
|
|
62
|
+
"@bunny-agent/manager": "0.9.59",
|
|
62
63
|
"@bunny-agent/apply-patch": "0.1.0",
|
|
63
|
-
"@bunny-agent/manager": "0.9.59-beta.7",
|
|
64
|
-
"@bunny-agent/runner-claude": "0.6.2",
|
|
65
64
|
"@bunny-agent/runner-codex": "0.6.2",
|
|
66
|
-
"@bunny-agent/runner-
|
|
67
|
-
"@bunny-agent/runner-harness": "0.1.1-beta.0",
|
|
65
|
+
"@bunny-agent/runner-claude": "0.6.2",
|
|
68
66
|
"@bunny-agent/runner-copilot": "0.1.0",
|
|
69
|
-
"@bunny-agent/runner-
|
|
70
|
-
"@bunny-agent/runner-
|
|
67
|
+
"@bunny-agent/runner-harness": "0.1.1-beta.0",
|
|
68
|
+
"@bunny-agent/runner-gemini": "0.6.2",
|
|
69
|
+
"@bunny-agent/runner-opencode": "0.6.2",
|
|
70
|
+
"@bunny-agent/runner-pi": "0.6.4-beta.0"
|
|
71
71
|
},
|
|
72
72
|
"scripts": {
|
|
73
73
|
"build": "tsc && pnpm bundle",
|