pi-long-task 0.1.3 → 0.3.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.
@@ -201,7 +201,7 @@ export interface WorkerSessionLike {
201
201
  compact?(customInstructions?: string): Promise<unknown>;
202
202
  dispose?(): void;
203
203
  getLastAssistantText?(): string | undefined;
204
- getSessionStats?(): unknown;
204
+ getSessionStats?(): unknown | Promise<unknown>;
205
205
  getContextUsage?(): unknown;
206
206
  sessionFile?: string;
207
207
  sessionId?: string;
@@ -246,6 +246,8 @@ export interface CapturedWorkerEvent {
246
246
  toolName?: string;
247
247
  isError?: boolean;
248
248
  note?: string;
249
+ usageCostTotal?: number;
250
+ usageCostKey?: string;
249
251
  }
250
252
 
251
253
  export interface SessionOutcome {
@@ -261,6 +263,8 @@ export interface SessionOutcome {
261
263
  contextObservations: string[];
262
264
  compactionEvents: string[];
263
265
  events: CapturedWorkerEvent[];
266
+ workerCostTotal: number;
267
+ workerCostSource?: string;
264
268
  shutdownRequested: boolean;
265
269
  timedOut: boolean;
266
270
  aborted: boolean;
@@ -345,6 +349,9 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
345
349
  let error: string | undefined;
346
350
  let finished = false;
347
351
  let turnCount = 0;
352
+ let messageUsageCostTotal = 0;
353
+ let hasMessageUsageCost = false;
354
+ let sessionStatsCostTotal: number | undefined;
348
355
 
349
356
  const prompt = buildTaskPrompt(options);
350
357
  const taskTimeoutSeconds = options.taskTimeoutSeconds ?? DEFAULT_TASK_TIMEOUT_SECONDS;
@@ -366,6 +373,22 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
366
373
  timers.clear();
367
374
  };
368
375
 
376
+ const messageUsageCostsByKey = new Map<string, number>();
377
+ const recordWorkerUsageCost = (cost: number | undefined, key: string | undefined) => {
378
+ if (cost === undefined) {
379
+ return;
380
+ }
381
+ hasMessageUsageCost = true;
382
+ if (!key) {
383
+ messageUsageCostTotal += cost;
384
+ return;
385
+ }
386
+
387
+ const previousCost = messageUsageCostsByKey.get(key) ?? 0;
388
+ messageUsageCostsByKey.set(key, cost);
389
+ messageUsageCostTotal += cost - previousCost;
390
+ };
391
+
369
392
  const schedule = (fn: () => void | Promise<void>, ms: number) => {
370
393
  const timer = setTimeout(() => {
371
394
  timers.delete(timer);
@@ -458,6 +481,7 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
458
481
  if (messageText) {
459
482
  assistantText = messageText;
460
483
  }
484
+ recordWorkerUsageCost(workerUsageCostFromEvent(event), workerUsageCostKeyFromEvent(event));
461
485
  break;
462
486
  }
463
487
  case "turn_end": {
@@ -538,6 +562,7 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
538
562
  assistantText = latestAssistantText(session, assistantText);
539
563
  sessionFile = session.sessionFile ?? sessionFile;
540
564
  sessionId = session.sessionId ?? sessionId;
565
+ sessionStatsCostTotal = await workerUsageCostFromSessionStats(session);
541
566
  session.dispose?.();
542
567
  }
543
568
  }
@@ -547,6 +572,10 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
547
572
  }
548
573
 
549
574
  const reportedStatus = parseReportedStatus(assistantText);
575
+ const capturedWorkerCost = selectWorkerCostTotal({
576
+ messageCostTotal: hasMessageUsageCost ? messageUsageCostTotal : undefined,
577
+ statsCostTotal: sessionStatsCostTotal,
578
+ });
550
579
  return {
551
580
  task: options.task,
552
581
  attempt: options.attempt,
@@ -560,6 +589,8 @@ export async function runWorkerTask(options: RunWorkerTaskOptions): Promise<Sess
560
589
  contextObservations,
561
590
  compactionEvents,
562
591
  events,
592
+ workerCostTotal: capturedWorkerCost.total,
593
+ workerCostSource: capturedWorkerCost.source,
563
594
  shutdownRequested,
564
595
  timedOut,
565
596
  aborted: aborted || Boolean(options.abortSignal?.aborted),
@@ -723,9 +754,15 @@ function summarizeWorkerEvent(event: unknown): CapturedWorkerEvent | undefined {
723
754
  };
724
755
  }
725
756
 
757
+ if (event.type === "message_end") {
758
+ const usageCostTotal = workerUsageCostFromEvent(event);
759
+ return usageCostTotal === undefined
760
+ ? { type: event.type }
761
+ : { type: event.type, usageCostTotal, usageCostKey: workerUsageCostKeyFromEvent(event) };
762
+ }
763
+
726
764
  if (
727
765
  event.type === "turn_end" ||
728
- event.type === "message_end" ||
729
766
  event.type === "compaction_start" ||
730
767
  event.type === "compaction_end" ||
731
768
  event.type === "agent_end" ||
@@ -738,6 +775,109 @@ function summarizeWorkerEvent(event: unknown): CapturedWorkerEvent | undefined {
738
775
  return undefined;
739
776
  }
740
777
 
778
+ export function workerUsageCostFromEvent(event: unknown): number | undefined {
779
+ if (!isRecord(event)) {
780
+ return undefined;
781
+ }
782
+
783
+ for (const candidate of [event.assistantMessage, event.message, event]) {
784
+ const cost = workerUsageCostFromAssistantMessage(candidate);
785
+ if (cost !== undefined) {
786
+ return cost;
787
+ }
788
+ }
789
+ return undefined;
790
+ }
791
+
792
+ export function workerUsageCostFromAssistantMessage(message: unknown): number | undefined {
793
+ if (!isRecord(message)) {
794
+ return undefined;
795
+ }
796
+ return usageCostTotal(message.usage);
797
+ }
798
+
799
+ export function workerUsageCostKeyFromEvent(event: unknown): string | undefined {
800
+ if (!isRecord(event)) {
801
+ return undefined;
802
+ }
803
+
804
+ for (const candidate of [event.assistantMessage, event.message, event]) {
805
+ const key = workerUsageCostKeyFromAssistantMessage(candidate);
806
+ if (key) {
807
+ return key;
808
+ }
809
+ }
810
+ return undefined;
811
+ }
812
+
813
+ function workerUsageCostKeyFromAssistantMessage(message: unknown): string | undefined {
814
+ if (!isRecord(message)) {
815
+ return undefined;
816
+ }
817
+
818
+ for (const keyName of ["id", "messageId", "uuid"] as const) {
819
+ const value = message[keyName];
820
+ if (typeof value === "string" && value) {
821
+ return `${keyName}:${value}`;
822
+ }
823
+ }
824
+ return undefined;
825
+ }
826
+
827
+ export function workerUsageCostFromStats(stats: unknown): number | undefined {
828
+ if (!isRecord(stats)) {
829
+ return undefined;
830
+ }
831
+
832
+ const directCost = finiteNonNegativeNumber(stats.cost);
833
+ if (directCost !== undefined) {
834
+ return directCost;
835
+ }
836
+
837
+ return usageCostTotal(stats.usage) ?? usageCostTotal(stats);
838
+ }
839
+
840
+ async function workerUsageCostFromSessionStats(session: WorkerSessionLike): Promise<number | undefined> {
841
+ if (!session.getSessionStats) {
842
+ return undefined;
843
+ }
844
+
845
+ try {
846
+ return workerUsageCostFromStats(await session.getSessionStats());
847
+ } catch {
848
+ return undefined;
849
+ }
850
+ }
851
+
852
+ function usageCostTotal(usage: unknown): number | undefined {
853
+ if (!isRecord(usage)) {
854
+ return undefined;
855
+ }
856
+
857
+ const cost = usage.cost;
858
+ if (isRecord(cost)) {
859
+ return finiteNonNegativeNumber(cost.total);
860
+ }
861
+ return finiteNonNegativeNumber(cost);
862
+ }
863
+
864
+ function selectWorkerCostTotal(options: { messageCostTotal: number | undefined; statsCostTotal: number | undefined }): {
865
+ total: number;
866
+ source?: string;
867
+ } {
868
+ if (options.statsCostTotal !== undefined) {
869
+ return { total: options.statsCostTotal, source: "session_stats" };
870
+ }
871
+ if (options.messageCostTotal !== undefined) {
872
+ return { total: options.messageCostTotal, source: "message_end" };
873
+ }
874
+ return { total: 0 };
875
+ }
876
+
877
+ function finiteNonNegativeNumber(value: unknown): number | undefined {
878
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined;
879
+ }
880
+
741
881
  function captureContextUsage(
742
882
  session: WorkerSessionLike | undefined,
743
883
  turnCount: number,