@agenticmail/claudecode 0.2.13 → 0.2.14
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/{chunk-UI556UPF.js → chunk-GVR4HTBB.js} +20 -1
- package/dist/{chunk-AXZGWR4M.js → chunk-IMSFAZWV.js} +4 -4
- package/dist/{chunk-F33EJZII.js → chunk-KQ3FJTHT.js} +1 -1
- package/dist/{chunk-XI7P3WSC.js → chunk-PDJOVOWH.js} +1 -1
- package/dist/{chunk-VAEQFJDW.js → chunk-QSOMPN2D.js} +68 -2
- package/dist/{chunk-GMYSDT2Y.js → chunk-UGB5UEYX.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/dispatcher-bin.js +2 -2
- package/dist/dispatcher.d.ts +15 -0
- package/dist/dispatcher.js +2 -2
- package/dist/http-routes.js +5 -5
- package/dist/index.js +6 -6
- package/dist/install.js +2 -2
- package/dist/status.js +2 -2
- package/dist/uninstall.js +2 -2
- package/package.json +2 -2
|
@@ -234,7 +234,26 @@ function renderPersonaBody(input) {
|
|
|
234
234
|
` 3. Look at To + CC across the thread \u2014 those are your teammates. They will each be woken on every reply-all just like you were.`,
|
|
235
235
|
` 4. **Check your prior contributions first.** In the search results from step 2, count how many messages are from \`${agent.email}\`. If you have already contributed your work to this thread, do NOT redo it on a new wake. Only re-contribute if (a) the latest reply has a NEW specific ask for you by name and you have not yet answered THAT ask, or (b) a teammate's reply genuinely changes the picture and your prior work needs an explicit revision. Redelivering the same content when a teammate posts an update is the most common multi-agent failure mode.`,
|
|
236
236
|
` 5. Decide if it's YOUR turn: are you addressed by name? Is the previous-stage handoff to your role? Is a question pending for you? **If a teammate replied within the last 60 seconds, assume they are handling this turn and stay silent** \u2014 simultaneous replies are noise. When in doubt, stay silent \u2014 over-replying creates noise.`,
|
|
237
|
-
` 6. If yes: \`${tool("reply_email")}({ uid, replyAll: true, text: "...", _account: "${agent.name}" })\`. Sign with your name
|
|
237
|
+
` 6. If yes: \`${tool("reply_email")}({ uid, replyAll: true, text: "...", _account: "${agent.name}" })\`. Sign with your name.`,
|
|
238
|
+
"",
|
|
239
|
+
` **HANDOFFS \u2014 read this carefully.** When you're delegating the next step to ONE specific teammate, you MUST pass \`wake: ["<their-name>"]\` in the same call. Reason: a reply-all keeps the ORIGINAL sender on the \`To:\` header, NOT your handoff target. So if Vesper just replied to the thread and you reply-all saying "Atlas \u2014 over to you", the resulting email lands with \`To: vesper\`, \`Cc: orion, atlas, ...\`. Without an explicit \`wake\`, every CC'd teammate gets a turn (cost), the dispatcher has no signal that Atlas is the assignee, and Atlas may stay silent assuming another teammate already took it \u2014 which is what the user calls "killing the task mid-work". \`wake: ["atlas"]\` is the authoritative signal: only Atlas thinks next, everyone else still receives the mail and stays informed. The body text is for humans + audit trail; the \`wake\` array is for the dispatcher.`,
|
|
240
|
+
"",
|
|
241
|
+
` **Examples.**`,
|
|
242
|
+
"",
|
|
243
|
+
"```",
|
|
244
|
+
`// Handing the next step to Atlas \u2014 Atlas wakes, everyone else stays informed but quiet.`,
|
|
245
|
+
`${tool("reply_email")}({ uid: 42, replyAll: true, _account: "${agent.name}",`,
|
|
246
|
+
` text: "Atlas \u2014 over to you. Spec is shared/slice-4-probe-spec.md. ...",`,
|
|
247
|
+
` wake: ["atlas"] })`,
|
|
248
|
+
``,
|
|
249
|
+
`// Broadcasting an update no specific teammate needs to act on \u2014 silent delivery.`,
|
|
250
|
+
`${tool("reply_email")}({ uid: 42, replyAll: true, _account: "${agent.name}",`,
|
|
251
|
+
` text: "Status: design doc is finalised at v2 \u2014 link below.",`,
|
|
252
|
+
` wake: [] })`,
|
|
253
|
+
`// (\`wake: []\` = "I'm broadcasting; nobody needs to wake on this.")`,
|
|
254
|
+
"```",
|
|
255
|
+
"",
|
|
256
|
+
` To bring a brand-new teammate into the thread, add them to CC AND name them in \`wake\`.`,
|
|
238
257
|
` 7. If no: \`mark_read\` and return. Silence IS a valid contribution.`,
|
|
239
258
|
"",
|
|
240
259
|
`**Closing a thread.** When the work is genuinely done and no more contributions are needed, send a wrap-up reply with one of these markers in the subject: \`[FINAL]\`, \`[DONE]\`, \`[CLOSED]\`, or \`[WRAP]\`. The dispatcher honours those markers and stops waking workers on any further replies to that thread. Use this when YOU are the one signing off the work, not as a routine ack.`,
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
status
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-PDJOVOWH.js";
|
|
4
4
|
import {
|
|
5
5
|
uninstall
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-UGB5UEYX.js";
|
|
7
7
|
import {
|
|
8
8
|
install
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-KQ3FJTHT.js";
|
|
10
10
|
import {
|
|
11
11
|
AgenticMailApiError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-GVR4HTBB.js";
|
|
13
13
|
|
|
14
14
|
// src/http-routes.ts
|
|
15
15
|
import { Router } from "express";
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
listPendingTasksForAgent,
|
|
5
5
|
renderPersonaBody,
|
|
6
6
|
resolveConfig
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-GVR4HTBB.js";
|
|
8
8
|
|
|
9
9
|
// src/persona-loader.ts
|
|
10
10
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -285,6 +285,11 @@ function isContextOverflowError(msg) {
|
|
|
285
285
|
const m = msg.toLowerCase();
|
|
286
286
|
return m.includes("prompt is too long") || m.includes("context_length_exceeded") || m.includes("context length exceeded") || m.includes("max tokens") || m.includes("maximum context") || m.includes("token limit");
|
|
287
287
|
}
|
|
288
|
+
function isRateLimitError(msg) {
|
|
289
|
+
if (!msg) return false;
|
|
290
|
+
const m = msg.toLowerCase();
|
|
291
|
+
return m.includes("429") || m.includes("rate limit") || m.includes("rate-limit") || m.includes("rate_limit") || m.includes("too many requests") || m.includes("quota exceeded") || m.includes("quota_exceeded") || m.includes("usage limit") || m.includes("limit reached") || m.includes("overloaded_error") || m.includes("insufficient_quota") || m.includes("weekly limit") || m.includes("daily limit");
|
|
292
|
+
}
|
|
288
293
|
async function runWorker(query, persona, userPrompt, agent, mcpServerName, mcpCommand, mcpArgs, mcpEnv, log, abortSignal, observer, cwd) {
|
|
289
294
|
const opts = {
|
|
290
295
|
systemPrompt: persona,
|
|
@@ -535,7 +540,7 @@ function taskPrompt(agent, event) {
|
|
|
535
540
|
`If you cannot complete the task, submit_result with { status: "failed", reason: "..." }. Never leave it unclaimed \u2014 that strands the caller until timeout.`
|
|
536
541
|
].join("\n");
|
|
537
542
|
}
|
|
538
|
-
var Dispatcher = class {
|
|
543
|
+
var Dispatcher = class _Dispatcher {
|
|
539
544
|
cfg;
|
|
540
545
|
maxConcurrent;
|
|
541
546
|
syncIntervalMs;
|
|
@@ -602,6 +607,15 @@ var Dispatcher = class {
|
|
|
602
607
|
*/
|
|
603
608
|
wakeCoalesce = /* @__PURE__ */ new Map();
|
|
604
609
|
wakeCoalesceMs;
|
|
610
|
+
/**
|
|
611
|
+
* In-memory queue of wakes the SDK rejected with a rate-limit
|
|
612
|
+
* error. See codex/dispatcher.ts for the full design rationale;
|
|
613
|
+
* the implementation is byte-for-byte identical here.
|
|
614
|
+
*/
|
|
615
|
+
deferredRetries = /* @__PURE__ */ new Map();
|
|
616
|
+
static RATE_LIMIT_RETRY_MS = 60 * 60 * 1e3;
|
|
617
|
+
// 1 hour
|
|
618
|
+
static RATE_LIMIT_MAX_ATTEMPTS = 24;
|
|
605
619
|
/** Wall-clock timestamp the dispatcher started. Surfaced via
|
|
606
620
|
* process-heartbeat so check_activity can show uptime. */
|
|
607
621
|
startedAtMs = Date.now();
|
|
@@ -729,6 +743,13 @@ var Dispatcher = class {
|
|
|
729
743
|
this.channels.clear();
|
|
730
744
|
for (const entry of this.wakeCoalesce.values()) clearTimeout(entry.timer);
|
|
731
745
|
this.wakeCoalesce.clear();
|
|
746
|
+
for (const entry of this.deferredRetries.values()) {
|
|
747
|
+
try {
|
|
748
|
+
clearTimeout(entry.timer);
|
|
749
|
+
} catch {
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
this.deferredRetries.clear();
|
|
732
753
|
try {
|
|
733
754
|
this.state.stop();
|
|
734
755
|
this.state.flushNow();
|
|
@@ -1435,6 +1456,19 @@ var Dispatcher = class {
|
|
|
1435
1456
|
const ok = workerResult?.ok === true;
|
|
1436
1457
|
const preview = workerResult?.ok ? workerResult.text : workerResult ? workerResult.error : "worker did not start";
|
|
1437
1458
|
writeLog(`worker_finished ok=${ok} chars=${preview.length}`);
|
|
1459
|
+
if (workerResult && !workerResult.ok && isRateLimitError(workerResult.error)) {
|
|
1460
|
+
this.scheduleRateLimitRetry(account, prompt, ctx, workerResult.error);
|
|
1461
|
+
} else if (workerResult?.ok) {
|
|
1462
|
+
const k = `${account.id}:${ctx.kind}:${ctx.uid ?? ctx.taskId ?? ""}`;
|
|
1463
|
+
const existing = this.deferredRetries.get(k);
|
|
1464
|
+
if (existing) {
|
|
1465
|
+
try {
|
|
1466
|
+
clearTimeout(existing.timer);
|
|
1467
|
+
} catch {
|
|
1468
|
+
}
|
|
1469
|
+
this.deferredRetries.delete(k);
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1438
1472
|
try {
|
|
1439
1473
|
logStream?.end();
|
|
1440
1474
|
} catch {
|
|
@@ -1457,6 +1491,38 @@ var Dispatcher = class {
|
|
|
1457
1491
|
});
|
|
1458
1492
|
}
|
|
1459
1493
|
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Schedule a 1-hour retry for a wake that the SDK rejected with a
|
|
1496
|
+
* rate-limit error. See the codex dispatcher's identical method
|
|
1497
|
+
* for the full design rationale — same budget, same cadence,
|
|
1498
|
+
* same in-memory-only state (catch-up scan handles restarts).
|
|
1499
|
+
*/
|
|
1500
|
+
scheduleRateLimitRetry(account, prompt, ctx, errorMsg) {
|
|
1501
|
+
const key = `${account.id}:${ctx.kind}:${ctx.uid ?? ctx.taskId ?? ""}`;
|
|
1502
|
+
const existing = this.deferredRetries.get(key);
|
|
1503
|
+
const attempts = (existing?.attempts ?? 0) + 1;
|
|
1504
|
+
if (attempts > _Dispatcher.RATE_LIMIT_MAX_ATTEMPTS) {
|
|
1505
|
+
this.log("warn", `[dispatcher] giving up on rate-limited retry for "${account.name}" (${ctx.kind}${ctx.uid ? " uid=" + ctx.uid : ""}) \u2014 exhausted ${attempts - 1} attempts over ~${((attempts - 1) * _Dispatcher.RATE_LIMIT_RETRY_MS / 36e5).toFixed(0)}h`);
|
|
1506
|
+
this.deferredRetries.delete(key);
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
if (existing) {
|
|
1510
|
+
try {
|
|
1511
|
+
clearTimeout(existing.timer);
|
|
1512
|
+
} catch {
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
const retryAtMs = Date.now() + _Dispatcher.RATE_LIMIT_RETRY_MS;
|
|
1516
|
+
const timer = setTimeout(() => {
|
|
1517
|
+
this.deferredRetries.delete(key);
|
|
1518
|
+
if (this.stopped) return;
|
|
1519
|
+
this.log("info", `[dispatcher] retrying rate-limited wake for "${account.name}" (${ctx.kind}${ctx.uid ? " uid=" + ctx.uid : ""}) \u2014 attempt ${attempts}/${_Dispatcher.RATE_LIMIT_MAX_ATTEMPTS}`);
|
|
1520
|
+
void this.spawnWorker(account, prompt, ctx);
|
|
1521
|
+
}, _Dispatcher.RATE_LIMIT_RETRY_MS);
|
|
1522
|
+
timer.unref?.();
|
|
1523
|
+
this.deferredRetries.set(key, { timer, attempts });
|
|
1524
|
+
this.log("warn", `[dispatcher] rate-limit hit for "${account.name}" (${ctx.kind}${ctx.uid ? " uid=" + ctx.uid : ""}) \u2014 retry scheduled for ${new Date(retryAtMs).toISOString()} (attempt ${attempts}/${_Dispatcher.RATE_LIMIT_MAX_ATTEMPTS}). SDK error: ${errorMsg.slice(0, 200)}`);
|
|
1525
|
+
}
|
|
1460
1526
|
/**
|
|
1461
1527
|
* Fire-and-forget POST to the API's worker-activity endpoints.
|
|
1462
1528
|
*
|
package/dist/cli.js
CHANGED
|
@@ -6,13 +6,13 @@ import {
|
|
|
6
6
|
} from "./chunk-B5JDOV32.js";
|
|
7
7
|
import {
|
|
8
8
|
status
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-PDJOVOWH.js";
|
|
10
10
|
import {
|
|
11
11
|
uninstall
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-UGB5UEYX.js";
|
|
13
13
|
import {
|
|
14
14
|
install
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-KQ3FJTHT.js";
|
|
16
16
|
import "./chunk-LO5EQSQA.js";
|
|
17
17
|
import "./chunk-US5FT2UB.js";
|
|
18
18
|
import {
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
listAccounts,
|
|
21
21
|
resolveConfig,
|
|
22
22
|
setAccountHost
|
|
23
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-GVR4HTBB.js";
|
|
24
24
|
|
|
25
25
|
// src/cli.ts
|
|
26
26
|
var GREEN = (s) => `\x1B[32m${s}\x1B[0m`;
|
package/dist/dispatcher-bin.js
CHANGED
package/dist/dispatcher.d.ts
CHANGED
|
@@ -222,6 +222,14 @@ declare class Dispatcher {
|
|
|
222
222
|
*/
|
|
223
223
|
private wakeCoalesce;
|
|
224
224
|
private wakeCoalesceMs;
|
|
225
|
+
/**
|
|
226
|
+
* In-memory queue of wakes the SDK rejected with a rate-limit
|
|
227
|
+
* error. See codex/dispatcher.ts for the full design rationale;
|
|
228
|
+
* the implementation is byte-for-byte identical here.
|
|
229
|
+
*/
|
|
230
|
+
private deferredRetries;
|
|
231
|
+
private static readonly RATE_LIMIT_RETRY_MS;
|
|
232
|
+
private static readonly RATE_LIMIT_MAX_ATTEMPTS;
|
|
225
233
|
/** Wall-clock timestamp the dispatcher started. Surfaced via
|
|
226
234
|
* process-heartbeat so check_activity can show uptime. */
|
|
227
235
|
private startedAtMs;
|
|
@@ -364,6 +372,13 @@ declare class Dispatcher {
|
|
|
364
372
|
}, prompt: string): string;
|
|
365
373
|
/** Acquire a concurrency slot, run a worker, release the slot. */
|
|
366
374
|
private spawnWorker;
|
|
375
|
+
/**
|
|
376
|
+
* Schedule a 1-hour retry for a wake that the SDK rejected with a
|
|
377
|
+
* rate-limit error. See the codex dispatcher's identical method
|
|
378
|
+
* for the full design rationale — same budget, same cadence,
|
|
379
|
+
* same in-memory-only state (catch-up scan handles restarts).
|
|
380
|
+
*/
|
|
381
|
+
private scheduleRateLimitRetry;
|
|
367
382
|
/**
|
|
368
383
|
* Fire-and-forget POST to the API's worker-activity endpoints.
|
|
369
384
|
*
|
package/dist/dispatcher.js
CHANGED
package/dist/http-routes.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createIntegrationRoutes
|
|
3
|
-
} from "./chunk-
|
|
4
|
-
import "./chunk-
|
|
5
|
-
import "./chunk-
|
|
6
|
-
import "./chunk-
|
|
3
|
+
} from "./chunk-IMSFAZWV.js";
|
|
4
|
+
import "./chunk-PDJOVOWH.js";
|
|
5
|
+
import "./chunk-UGB5UEYX.js";
|
|
6
|
+
import "./chunk-KQ3FJTHT.js";
|
|
7
7
|
import "./chunk-LO5EQSQA.js";
|
|
8
8
|
import "./chunk-US5FT2UB.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-GVR4HTBB.js";
|
|
10
10
|
export {
|
|
11
11
|
createIntegrationRoutes
|
|
12
12
|
};
|
package/dist/index.js
CHANGED
|
@@ -6,19 +6,19 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
Dispatcher,
|
|
8
8
|
loadPersonaForAgent
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-QSOMPN2D.js";
|
|
10
10
|
import {
|
|
11
11
|
createIntegrationRoutes
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IMSFAZWV.js";
|
|
13
13
|
import {
|
|
14
14
|
status
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-PDJOVOWH.js";
|
|
16
16
|
import {
|
|
17
17
|
uninstall
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-UGB5UEYX.js";
|
|
19
19
|
import {
|
|
20
20
|
install
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-KQ3FJTHT.js";
|
|
22
22
|
import "./chunk-LO5EQSQA.js";
|
|
23
23
|
import "./chunk-US5FT2UB.js";
|
|
24
24
|
import {
|
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
renderPersonaBody,
|
|
33
33
|
renderSubagentMarkdown,
|
|
34
34
|
resolveConfig
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-GVR4HTBB.js";
|
|
36
36
|
export {
|
|
37
37
|
AgenticMailApiError,
|
|
38
38
|
Dispatcher,
|
package/dist/install.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
install,
|
|
3
3
|
selectExposableAgents
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-KQ3FJTHT.js";
|
|
5
5
|
import "./chunk-LO5EQSQA.js";
|
|
6
6
|
import "./chunk-US5FT2UB.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-GVR4HTBB.js";
|
|
8
8
|
export {
|
|
9
9
|
install,
|
|
10
10
|
selectExposableAgents
|
package/dist/status.js
CHANGED
package/dist/uninstall.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agenticmail/claudecode",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.14",
|
|
4
4
|
"description": "Claude Code integration for AgenticMail — surfaces every AgenticMail agent as a native Claude Code subagent so any Claude Code session can delegate to them with the Agent tool",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"prepublishOnly": "npm run build"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@agenticmail/core": "^0.9.
|
|
50
|
+
"@agenticmail/core": "^0.9.4",
|
|
51
51
|
"@agenticmail/mcp": "^0.9.4",
|
|
52
52
|
"@anthropic-ai/claude-agent-sdk": "^0.2.140"
|
|
53
53
|
},
|