@openape/ape-agent 2.9.1 → 2.10.0

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/bridge.mjs CHANGED
@@ -802,17 +802,58 @@ ${e.cyan(d)}
802
802
  }
803
803
  });
804
804
 
805
- // ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/quote.js
805
+ // ../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/quote.js
806
806
  var require_quote = __commonJS({
807
- "../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/quote.js"(exports, module) {
807
+ "../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/quote.js"(exports, module) {
808
808
  "use strict";
809
+ var OPS = [
810
+ "||",
811
+ "&&",
812
+ ";;",
813
+ "|&",
814
+ "<(",
815
+ "<<<",
816
+ ">>",
817
+ ">&",
818
+ "<&",
819
+ "&",
820
+ ";",
821
+ "(",
822
+ ")",
823
+ "|",
824
+ "<",
825
+ ">"
826
+ ];
827
+ var LINE_TERMINATORS = /[\n\r\u2028\u2029]/;
828
+ var GLOB_SHELL_SPECIAL = /[\s#!"$&'():;<=>@\\^`|]/g;
809
829
  module.exports = function quote(xs) {
810
830
  return xs.map(function(s2) {
811
831
  if (s2 === "") {
812
832
  return "''";
813
833
  }
814
834
  if (s2 && typeof s2 === "object") {
815
- return s2.op.replace(/(.)/g, "\\$1");
835
+ if (s2.op === "glob") {
836
+ if (typeof s2.pattern !== "string") {
837
+ throw new TypeError("glob token requires a string `pattern`");
838
+ }
839
+ if (LINE_TERMINATORS.test(s2.pattern)) {
840
+ throw new TypeError("glob `pattern` must not contain line terminators");
841
+ }
842
+ return s2.pattern.replace(GLOB_SHELL_SPECIAL, "\\$&");
843
+ }
844
+ if (typeof s2.op === "string") {
845
+ if (OPS.indexOf(s2.op) < 0) {
846
+ throw new TypeError("invalid `op` value: " + JSON.stringify(s2.op));
847
+ }
848
+ return s2.op.replace(/[\s\S]/g, "\\$&");
849
+ }
850
+ if (typeof s2.comment === "string") {
851
+ if (LINE_TERMINATORS.test(s2.comment)) {
852
+ throw new TypeError("`comment` must not contain line terminators");
853
+ }
854
+ return "#" + s2.comment;
855
+ }
856
+ throw new TypeError("unrecognized object token shape");
816
857
  }
817
858
  if (/["\s\\]/.test(s2) && !/'/.test(s2)) {
818
859
  return "'" + s2.replace(/(['])/g, "\\$1") + "'";
@@ -826,9 +867,9 @@ var require_quote = __commonJS({
826
867
  }
827
868
  });
828
869
 
829
- // ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/parse.js
870
+ // ../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/parse.js
830
871
  var require_parse = __commonJS({
831
- "../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/parse.js"(exports, module) {
872
+ "../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/parse.js"(exports, module) {
832
873
  "use strict";
833
874
  var CONTROL = "(?:" + [
834
875
  "\\|\\|",
@@ -1023,9 +1064,9 @@ var require_parse = __commonJS({
1023
1064
  }
1024
1065
  });
1025
1066
 
1026
- // ../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/index.js
1067
+ // ../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/index.js
1027
1068
  var require_shell_quote = __commonJS({
1028
- "../../node_modules/.pnpm/shell-quote@1.8.3/node_modules/shell-quote/index.js"(exports) {
1069
+ "../../node_modules/.pnpm/shell-quote@1.8.4/node_modules/shell-quote/index.js"(exports) {
1029
1070
  "use strict";
1030
1071
  exports.quote = require_quote();
1031
1072
  exports.parse = require_parse();
@@ -3130,7 +3171,7 @@ function extractOption(args, name) {
3130
3171
  return void 0;
3131
3172
  }
3132
3173
 
3133
- // ../../packages/apes/dist/chunk-NYJSBFLG.js
3174
+ // ../../packages/apes/dist/chunk-MMBFV5WN.js
3134
3175
  init_chunk_OBF7IMQ2();
3135
3176
  var debug = process.argv.includes("--debug");
3136
3177
 
@@ -3156,13 +3197,14 @@ function capStdio(s2) {
3156
3197
  return `${buf.subarray(0, MAX_STDIO_BYTES).toString("utf8")}
3157
3198
  [truncated to ${MAX_STDIO_BYTES} bytes]`;
3158
3199
  }
3159
- function runApeShell(cmd, timeoutMs = DEFAULT_TIMEOUT_MS) {
3200
+ function runApeShell(cmd, timeoutMs = DEFAULT_TIMEOUT_MS, cwd) {
3160
3201
  const bypass = process.env.OPENAPE_BYPASS_APE_SHELL === "1";
3161
3202
  const [execBin, execArgs] = bypass ? ["/bin/bash", ["-c", cmd]] : [BIN, ["-c", cmd]];
3162
3203
  return new Promise((resolveResult) => {
3163
3204
  const child = spawn(execBin, execArgs, {
3164
3205
  env: { ...process.env, APE_WAIT: "1" },
3165
- stdio: ["ignore", "pipe", "pipe"]
3206
+ stdio: ["ignore", "pipe", "pipe"],
3207
+ ...cwd ? { cwd } : {}
3166
3208
  });
3167
3209
  let stdout2 = "";
3168
3210
  let stderr = "";
@@ -4141,6 +4183,9 @@ var REVIEW_SYSTEM = [
4141
4183
  // src/cron-runner.ts
4142
4184
  var TASK_CACHE_DIR = join4(homedir6(), ".openape", "agent", "tasks");
4143
4185
  var AGENT_CONFIG_PATH = join4(homedir6(), ".openape", "agent", "agent.json");
4186
+ function resolveRecipeDir() {
4187
+ return process.env.OPENAPE_RECIPE_DEV_DIR || join4(homedir6(), "recipe");
4188
+ }
4144
4189
  var TASK_THREADS_PATH = join4(homedir6(), ".openape", "agent", "task-threads.json");
4145
4190
  var TICK_INTERVAL_MS = 6e4;
4146
4191
  function parseField(token, range, allowStep) {
@@ -4207,6 +4252,9 @@ ${tail(out, 2500)}`);
4207
4252
  ${tail(err, 2500)}`);
4208
4253
  return parts.join("\n\n");
4209
4254
  }
4255
+ function shouldReportCommandRun(exitCode, stdout2, stderr) {
4256
+ return exitCode !== 0 || `${stdout2}${stderr}`.trim() !== "";
4257
+ }
4210
4258
  function readSystemPrompt() {
4211
4259
  if (!existsSync3(AGENT_CONFIG_PATH)) return "";
4212
4260
  try {
@@ -4327,13 +4375,15 @@ var CronRunner = class {
4327
4375
  async runTask(sessionId, systemPrompt, spec) {
4328
4376
  if (spec.command) {
4329
4377
  try {
4330
- const res = await runApeShell(spec.command, 30 * 60 * 1e3);
4378
+ const recipeDir = resolveRecipeDir();
4379
+ const res = await runApeShell(spec.command, 30 * 60 * 1e3, existsSync3(recipeDir) ? recipeDir : void 0);
4331
4380
  const turn = this.pending.get(sessionId);
4332
4381
  if (!turn) return;
4333
4382
  turn.status = res.exit_code === 0 ? "ok" : "error";
4334
4383
  turn.accumulated = composeTaskOutput(spec.command, res.exit_code, res.stdout, res.stderr);
4335
4384
  await this.finaliseRun(turn, 1);
4336
- await this.postResult(sessionId, turn);
4385
+ if (shouldReportCommandRun(res.exit_code, res.stdout, res.stderr))
4386
+ await this.postResult(sessionId, turn);
4337
4387
  this.pending.delete(sessionId);
4338
4388
  } catch (err) {
4339
4389
  const turn = this.pending.get(sessionId);
@@ -4711,6 +4761,8 @@ function createThrottle(fn, intervalMs) {
4711
4761
 
4712
4762
  // src/thread-session.ts
4713
4763
  var PATCH_INTERVAL_MS = 300;
4764
+ var NO_ACTIVITY_TIMEOUT_MS = 6e4;
4765
+ var NO_RESPONSE_MESSAGE = "(no response from the model backend \u2014 it may be unavailable or its API auth expired; nothing was changed, please retry)";
4714
4766
  var ThreadSession = class {
4715
4767
  constructor(deps) {
4716
4768
  this.deps = deps;
@@ -4772,6 +4824,18 @@ var ThreadSession = class {
4772
4824
  };
4773
4825
  const { systemPrompt, tools } = this.deps.resolveConfig();
4774
4826
  await this.backfillHistoryOnce(replyToMessageId, body);
4827
+ let sawActivity = false;
4828
+ let turnSettled = false;
4829
+ const settleOnce = () => {
4830
+ if (turnSettled) return true;
4831
+ turnSettled = true;
4832
+ return false;
4833
+ };
4834
+ const watchdog = setTimeout(() => {
4835
+ if (sawActivity || this.active !== turn || settleOnce()) return;
4836
+ this.deps.log(`turn watchdog: no model activity in ${NO_ACTIVITY_TIMEOUT_MS}ms \u2014 failing turn (room=${this.deps.roomId} thread=${this.deps.threadId})`);
4837
+ void this.failTurn(NO_RESPONSE_MESSAGE);
4838
+ }, NO_ACTIVITY_TIMEOUT_MS);
4775
4839
  try {
4776
4840
  const result = await runLoop({
4777
4841
  config: this.deps.runtimeConfig,
@@ -4782,11 +4846,13 @@ var ThreadSession = class {
4782
4846
  history: this.history,
4783
4847
  handlers: {
4784
4848
  onTextDelta: (delta) => {
4849
+ sawActivity = true;
4785
4850
  if (!this.active) return;
4786
4851
  this.active.accumulated += delta;
4787
4852
  this.active.throttle.schedule();
4788
4853
  },
4789
4854
  onToolCall: ({ name }) => {
4855
+ sawActivity = true;
4790
4856
  this.deps.log(`[${this.deps.roomId}/${this.deps.threadId.slice(0, 8)}] tool_call: ${name}`);
4791
4857
  void setStatus(`\u{1F527} ${name}`);
4792
4858
  },
@@ -4800,15 +4866,23 @@ var ThreadSession = class {
4800
4866
  }
4801
4867
  }
4802
4868
  });
4869
+ clearTimeout(watchdog);
4870
+ if (settleOnce()) return;
4803
4871
  this.history.push({ role: "user", content: body });
4804
4872
  if (result.finalMessage) {
4805
4873
  this.history.push({ role: "assistant", content: result.finalMessage });
4806
4874
  }
4807
4875
  if (result.status === "error") {
4808
4876
  this.deps.log(`runtime done with status=error (room=${this.deps.roomId} thread=${this.deps.threadId})`);
4877
+ if (!turn.accumulated) {
4878
+ await this.failTurn("(the model run ended with an error and produced no output \u2014 please retry)");
4879
+ return;
4880
+ }
4809
4881
  }
4810
4882
  await this.endTurn();
4811
4883
  } catch (err) {
4884
+ clearTimeout(watchdog);
4885
+ if (settleOnce()) return;
4812
4886
  const message = err instanceof Error ? err.message : String(err);
4813
4887
  this.deps.log(`runtime error (room=${this.deps.roomId} thread=${this.deps.threadId}): ${message}`);
4814
4888
  await this.failTurn(`(runtime error: ${message})`);