@tablation/crew 0.68.0 → 0.68.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/dist/cli.js +51 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3887,6 +3887,9 @@ function ticketMentions(text) {
|
|
|
3887
3887
|
var TicketAttributionTracker = class {
|
|
3888
3888
|
#tokensByTicket = /* @__PURE__ */ new Map();
|
|
3889
3889
|
#current;
|
|
3890
|
+
/** Tracker record uuid → ticket key, learned when a write names both (a claim resolves the key from the last mention). */
|
|
3891
|
+
#keyByRecord = /* @__PURE__ */ new Map();
|
|
3892
|
+
#lastBy = {};
|
|
3890
3893
|
/** The ticket key most recently named in the transcript, or undefined before any. */
|
|
3891
3894
|
get current() {
|
|
3892
3895
|
return this.#current;
|
|
@@ -3903,6 +3906,37 @@ var TicketAttributionTracker = class {
|
|
|
3903
3906
|
if (this.#current === void 0 || tokens <= 0) return;
|
|
3904
3907
|
this.#tokensByTicket.set(this.#current, (this.#tokensByTicket.get(this.#current) ?? 0) + tokens);
|
|
3905
3908
|
}
|
|
3909
|
+
/**
|
|
3910
|
+
* Record a tool call if it is a ticket-targeted tracker write (claim,
|
|
3911
|
+
* hand-off or comment). The ticket key comes from a record uuid seen on an
|
|
3912
|
+
* earlier write when known, else from the key last named in the transcript
|
|
3913
|
+
* (a claim or hand-off announces its ticket). A comment on a record never
|
|
3914
|
+
* seen before is ignored: its uuid cannot be resolved to a key.
|
|
3915
|
+
*/
|
|
3916
|
+
noteWrite(tool, input) {
|
|
3917
|
+
const w = classifyWrite(tool, input);
|
|
3918
|
+
if (!w) return;
|
|
3919
|
+
let key = w.recordId ? this.#keyByRecord.get(w.recordId) : void 0;
|
|
3920
|
+
if (w.kind !== "comment") key ??= this.#current;
|
|
3921
|
+
if (!key) return;
|
|
3922
|
+
if (w.kind !== "comment" && w.recordId) this.#keyByRecord.set(w.recordId, key);
|
|
3923
|
+
this.#lastBy[w.kind] = key;
|
|
3924
|
+
}
|
|
3925
|
+
/**
|
|
3926
|
+
* How the attribution is decided: a hand-off write beats a claim, a claim
|
|
3927
|
+
* beats a comment (so a follow-up ticket filed or commented on while
|
|
3928
|
+
* working never displaces the claimed one), and any write beats the
|
|
3929
|
+
* mention-token heuristic, which is only the fallback for runs that made
|
|
3930
|
+
* no ticket-targeted write. The pre-run hint is last.
|
|
3931
|
+
*/
|
|
3932
|
+
decide(hint) {
|
|
3933
|
+
for (const by of ["handoff", "claim", "comment"]) {
|
|
3934
|
+
const ticket = this.#lastBy[by];
|
|
3935
|
+
if (ticket) return { ticket, by };
|
|
3936
|
+
}
|
|
3937
|
+
if (this.#tokensByTicket.size > 0) return { ticket: this.winner(hint), by: "mentions" };
|
|
3938
|
+
return { ticket: hint, by: "hint" };
|
|
3939
|
+
}
|
|
3906
3940
|
/**
|
|
3907
3941
|
* The ticket key the run spent the most tokens on, or `fallback` (the
|
|
3908
3942
|
* pre-run poll hint) when the transcript never named one — an
|
|
@@ -3926,6 +3960,20 @@ function isClaimWrite(tool, input) {
|
|
|
3926
3960
|
const body = input?.body;
|
|
3927
3961
|
return typeof body === "object" && body !== null && body.status === "in_progress";
|
|
3928
3962
|
}
|
|
3963
|
+
var HANDOFF_STATUSES = /* @__PURE__ */ new Set(["fixed", "verified", "needs_info", "accepted"]);
|
|
3964
|
+
function classifyWrite(tool, input) {
|
|
3965
|
+
if (!tool) return void 0;
|
|
3966
|
+
const body = input?.body;
|
|
3967
|
+
if (typeof body !== "object" || body === null) return void 0;
|
|
3968
|
+
const b = body;
|
|
3969
|
+
if (/records_controller_update$/.test(tool)) {
|
|
3970
|
+
const recordId = typeof input?.recordId === "string" ? input.recordId : void 0;
|
|
3971
|
+
if (b.status === "in_progress" || b.status === "qa") return { kind: "claim", recordId };
|
|
3972
|
+
if (typeof b.status === "string" && HANDOFF_STATUSES.has(b.status)) return { kind: "handoff", recordId };
|
|
3973
|
+
}
|
|
3974
|
+
if (/records_controller_create$/.test(tool) && typeof b.ticket_id === "string") return { kind: "comment", recordId: b.ticket_id };
|
|
3975
|
+
return void 0;
|
|
3976
|
+
}
|
|
3929
3977
|
|
|
3930
3978
|
// src/agent.ts
|
|
3931
3979
|
var DIGEST_MAX_AGE_SECONDS = 600;
|
|
@@ -4216,6 +4264,7 @@ var RunObserver = class {
|
|
|
4216
4264
|
let turnText = "";
|
|
4217
4265
|
for (const ev of events) if ((ev.kind === "thought" || ev.kind === "text") && ev.text) this.attribution.note(ev.text);
|
|
4218
4266
|
for (const ev of events) {
|
|
4267
|
+
if (ev.kind === "tool") this.attribution.noteWrite(ev.tool, ev.input);
|
|
4219
4268
|
if (ev.kind === "tool" && isClaimWrite(ev.tool, ev.input)) {
|
|
4220
4269
|
const claimed = this.attribution.current;
|
|
4221
4270
|
if (claimed && claimed !== this.liveTicket) {
|
|
@@ -4300,12 +4349,13 @@ function writeRunMeta(id, startedAt, liveTicket, extra) {
|
|
|
4300
4349
|
}
|
|
4301
4350
|
}
|
|
4302
4351
|
async function finishRun(id, obs, emit, startedAt, end, agentLogKey) {
|
|
4303
|
-
const attributedTicket = obs.attribution.
|
|
4352
|
+
const { ticket: attributedTicket, by: attributedBy } = obs.attribution.decide(obs.liveTicket);
|
|
4304
4353
|
const identity = { toolchain: id.toolchain, harness: id.harness, provider: id.provider };
|
|
4305
4354
|
const { result } = obs;
|
|
4306
4355
|
try {
|
|
4307
4356
|
writeRunMeta(id, startedAt, obs.liveTicket, {
|
|
4308
4357
|
attributedTicket: attributedTicket ?? null,
|
|
4358
|
+
attributedBy,
|
|
4309
4359
|
running: void 0,
|
|
4310
4360
|
exitCode: end.code,
|
|
4311
4361
|
...end.interrupted ? { interrupted: end.interrupted } : {},
|
package/package.json
CHANGED