@openape/ape-agent 2.4.0 → 2.5.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.
Files changed (2) hide show
  1. package/dist/bridge.mjs +50 -0
  2. package/package.json +1 -1
package/dist/bridge.mjs CHANGED
@@ -1366,6 +1366,19 @@ var ChatApi = class {
1366
1366
  });
1367
1367
  return result;
1368
1368
  }
1369
+ /**
1370
+ * Fetch the most recent `limit` messages in a thread, oldest-first.
1371
+ * Used by ThreadSession to seed `history` so the agent has the
1372
+ * full conversation context after a bridge restart — otherwise it
1373
+ * only sees messages that arrived via WS since the process boot.
1374
+ */
1375
+ async listMessages(roomId, threadId, limit = 50) {
1376
+ const url = `${this.endpoint}/api/rooms/${encodeURIComponent(roomId)}/messages?thread_id=${encodeURIComponent(threadId)}&limit=${limit}`;
1377
+ return await ofetch5(url, {
1378
+ method: "GET",
1379
+ headers: { Authorization: await this.bearer() }
1380
+ });
1381
+ }
1369
1382
  async requestContact(peerEmail) {
1370
1383
  const url = `${this.endpoint}/api/contacts`;
1371
1384
  return await ofetch5(url, {
@@ -4045,6 +4058,14 @@ var ThreadSession = class {
4045
4058
  active;
4046
4059
  queue = [];
4047
4060
  history = [];
4061
+ /**
4062
+ * Whether we've already backfilled history from the chat server.
4063
+ * Done lazily on the first turn so a freshly-created ThreadSession
4064
+ * (e.g. after a bridge restart) sees the full conversation context,
4065
+ * not just the message that woke it up. We skip the message that
4066
+ * triggered the turn — runLoop adds it via `userMessage`.
4067
+ */
4068
+ backfilled = false;
4048
4069
  /**
4049
4070
  * No-op placeholder kept for API compatibility with the previous
4050
4071
  * RPC-listener model where dispose() detached the listener.
@@ -4089,6 +4110,7 @@ var ThreadSession = class {
4089
4110
  }
4090
4111
  };
4091
4112
  const { systemPrompt, tools } = this.deps.resolveConfig();
4113
+ await this.backfillHistoryOnce(replyToMessageId, body);
4092
4114
  try {
4093
4115
  const result = await runLoop({
4094
4116
  config: this.deps.runtimeConfig,
@@ -4131,6 +4153,33 @@ var ThreadSession = class {
4131
4153
  await this.failTurn(`(runtime error: ${message})`);
4132
4154
  }
4133
4155
  }
4156
+ /**
4157
+ * Fetch recent chat history for this thread and seed `this.history`.
4158
+ * Idempotent — only runs once per ThreadSession instance. Skips the
4159
+ * placeholder we just posted plus the inbound message that triggered
4160
+ * this turn (runLoop's `userMessage` handles that one).
4161
+ *
4162
+ * Failures are non-fatal: we log and continue with empty history.
4163
+ * That preserves the pre-backfill behaviour rather than failing the
4164
+ * turn over a transient chat-server hiccup.
4165
+ */
4166
+ async backfillHistoryOnce(currentMessageId, currentBody) {
4167
+ if (this.backfilled) return;
4168
+ this.backfilled = true;
4169
+ try {
4170
+ const rows = await this.deps.chat.listMessages(this.deps.roomId, this.deps.threadId, 50);
4171
+ for (const row of rows) {
4172
+ if (row.id === currentMessageId) continue;
4173
+ if (!row.body || row.body.length === 0) continue;
4174
+ if (row.body === currentBody && row.senderEmail !== this.deps.selfEmail) continue;
4175
+ const role = row.senderEmail === this.deps.selfEmail ? "assistant" : "user";
4176
+ this.history.push({ role, content: row.body });
4177
+ }
4178
+ this.deps.log(`[${this.deps.roomId}/${this.deps.threadId.slice(0, 8)}] backfilled ${this.history.length} message(s) from chat history`);
4179
+ } catch (err) {
4180
+ this.deps.log(`[${this.deps.roomId}/${this.deps.threadId.slice(0, 8)}] backfill failed (continuing with empty history): ${err instanceof Error ? err.message : String(err)}`);
4181
+ }
4182
+ }
4134
4183
  /**
4135
4184
  * Stream-end: flush any pending throttled body PATCH, then mark the
4136
4185
  * message as no-longer-streaming. The combined call also triggers
@@ -4381,6 +4430,7 @@ var Bridge = class {
4381
4430
  })
4382
4431
  };
4383
4432
  },
4433
+ selfEmail: this.selfEmail,
4384
4434
  maxSteps: this.cfg.maxSteps,
4385
4435
  log
4386
4436
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openape/ape-agent",
3
- "version": "2.4.0",
3
+ "version": "2.5.1",
4
4
  "description": "OpenApe agent runtime: per-agent process that connects to chat.openape.ai, runs the LLM loop with tools + cron tasks, and streams replies back to owners.",
5
5
  "type": "module",
6
6
  "license": "MIT",