happy-imou-cloud 2.0.22 → 2.1.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.
Files changed (35) hide show
  1. package/bin/happy-cloud.mjs +1 -1
  2. package/dist/{BaseReasoningProcessor-CJVv1aNR.cjs → BaseReasoningProcessor-C9mH8EVn.cjs} +3 -3
  3. package/dist/{BaseReasoningProcessor-mIqqngd3.mjs → BaseReasoningProcessor-DQkzwRuf.mjs} +3 -3
  4. package/dist/ProviderSelectionHandler-5Dedbm8j.cjs +265 -0
  5. package/dist/ProviderSelectionHandler-BlrrLPlo.mjs +261 -0
  6. package/dist/{api-DP-RQUao.cjs → api-Bd-MnOS4.cjs} +24 -2
  7. package/dist/{api-DrijKeDb.mjs → api-w_CUxb9Q.mjs} +25 -3
  8. package/dist/{command-BZphfJrt.cjs → command-DoDmHNxR.cjs} +3 -3
  9. package/dist/{command--vV6BSsL.mjs → command-mTWwCqTY.mjs} +3 -3
  10. package/dist/{index-CqCEZDFi.cjs → index-BQmJ4NAa.cjs} +199 -79
  11. package/dist/{index-BIki80pQ.mjs → index-GuXV-pxB.mjs} +196 -76
  12. package/dist/index.cjs +3 -3
  13. package/dist/index.mjs +3 -3
  14. package/dist/lib.cjs +1 -1
  15. package/dist/lib.d.cts +95 -92
  16. package/dist/lib.d.mts +95 -92
  17. package/dist/lib.mjs +1 -1
  18. package/dist/{persistence-yVTbf_Ng.cjs → persistence-BL06LLVz.cjs} +1 -1
  19. package/dist/{persistence-C3NBdZdz.mjs → persistence-MSy70is3.mjs} +1 -1
  20. package/dist/{registerKillSessionHandler-CHEj7UjN.mjs → registerKillSessionHandler-CjWfUfc3.mjs} +428 -13
  21. package/dist/{registerKillSessionHandler-QmBN446A.cjs → registerKillSessionHandler-D9kwxy6B.cjs} +430 -12
  22. package/dist/{runClaude-BuI6OOEv.cjs → runClaude-D2ZEXue8.cjs} +11 -9
  23. package/dist/{runClaude-D0DD_Ya5.mjs → runClaude-DpZ95Twb.mjs} +8 -6
  24. package/dist/{runCodex-BzZ0jODI.mjs → runCodex-CJwaep2R.mjs} +9 -7
  25. package/dist/{runCodex-1jTTmCvq.cjs → runCodex-Dz_1ho8d.cjs} +12 -10
  26. package/dist/{runGemini-Bx2SYAyG.mjs → runGemini-BehqjM73.mjs} +192 -71
  27. package/dist/{runGemini-1gJRE8oT.cjs → runGemini-Dfu6LltX.cjs} +192 -71
  28. package/package.json +1 -1
  29. package/scripts/build.mjs +66 -66
  30. package/scripts/devtools/README.md +9 -9
  31. package/scripts/e2e/fake-codex-acp-agent.mjs +139 -139
  32. package/scripts/e2e/local-server-session-roundtrip.mjs +1063 -1063
  33. package/scripts/release-smoke.mjs +3 -0
  34. package/dist/ProviderSelectionHandler-BjLyIfSR.mjs +0 -673
  35. package/dist/ProviderSelectionHandler-e4zL4Y5_.cjs +0 -680
@@ -1,8 +1,8 @@
1
- import { i as initialMachineMetadata, e as projectPath, R as RuntimeShell, h as resolveCanonicalToolNameV2, f as formatDisplayMessage } from './index-BIki80pQ.mjs';
2
- import { readSettings } from './persistence-C3NBdZdz.mjs';
1
+ import { i as initialMachineMetadata, e as projectPath, R as RuntimeShell, h as resolveCanonicalToolNameV2, f as formatDisplayMessage } from './index-GuXV-pxB.mjs';
2
+ import { readSettings } from './persistence-MSy70is3.mjs';
3
3
  import os from 'node:os';
4
4
  import { resolve } from 'node:path';
5
- import { c as configuration, p as packageJson, l as logger } from './api-DrijKeDb.mjs';
5
+ import { c as configuration, p as packageJson, H as HAPPY_ORG_TURN_REPORT_TAG, d as HAPPY_ORG_SUMMARY_MAX_LENGTH, f as HAPPY_ORG_REPEAT_THRESHOLD, l as logger } from './api-w_CUxb9Q.mjs';
6
6
  import { randomUUID } from 'node:crypto';
7
7
  import { createHash } from 'crypto';
8
8
  import 'axios';
@@ -259,15 +259,18 @@ async function closeProviderSession(session, opts = {}) {
259
259
  firstError = error;
260
260
  }
261
261
  };
262
- if (opts.archiveReason) {
262
+ if (opts.archiveOnClose || opts.archiveReason) {
263
263
  try {
264
- session.updateMetadata((currentMetadata) => ({
265
- ...currentMetadata,
266
- lifecycleState: "archived",
267
- lifecycleStateSince: Date.now(),
268
- archivedBy: opts.archivedBy ?? "cli",
269
- archiveReason: opts.archiveReason
270
- }));
264
+ session.updateMetadata((currentMetadata) => {
265
+ const { archiveReason: _existingArchiveReason, ...metadataWithoutArchiveReason } = currentMetadata;
266
+ return {
267
+ ...metadataWithoutArchiveReason,
268
+ lifecycleState: "archived",
269
+ lifecycleStateSince: Date.now(),
270
+ archivedBy: opts.archivedBy ?? "cli",
271
+ ...opts.archiveReason ? { archiveReason: opts.archiveReason } : {}
272
+ };
273
+ });
271
274
  } catch (error) {
272
275
  captureError(error);
273
276
  }
@@ -297,7 +300,7 @@ function createAbortError() {
297
300
  error.name = "AbortError";
298
301
  return error;
299
302
  }
300
- async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 12e4) {
303
+ async function waitForResponseCompleteWithAbort(backend, signal, timeoutMs = 10 * 6e4) {
301
304
  if (!backend.waitForResponseComplete) {
302
305
  return;
303
306
  }
@@ -351,6 +354,418 @@ async function syncControlledByUserState(sessionClient, controlledByUser) {
351
354
  });
352
355
  }
353
356
 
357
+ function normalizeOptionalText(value) {
358
+ if (typeof value !== "string") {
359
+ return null;
360
+ }
361
+ const trimmed = value.trim();
362
+ return trimmed.length > 0 ? trimmed : null;
363
+ }
364
+ function normalizeSummaryText(value) {
365
+ const normalized = normalizeOptionalText(value);
366
+ return normalized ? normalized.replace(/\s+/g, " ").slice(0, HAPPY_ORG_SUMMARY_MAX_LENGTH) : null;
367
+ }
368
+ function cloneHappyOrgMetadata(happyOrg) {
369
+ return {
370
+ taskContext: happyOrg?.taskContext ? { ...happyOrg.taskContext } : void 0,
371
+ runtime: happyOrg?.runtime ? { ...happyOrg.runtime } : void 0,
372
+ activeOwner: happyOrg?.activeOwner ? { ...happyOrg.activeOwner } : null,
373
+ repeat: happyOrg?.repeat ? {
374
+ threshold: happyOrg.repeat.threshold,
375
+ fingerprints: Object.fromEntries(
376
+ Object.entries(happyOrg.repeat.fingerprints ?? {}).map(([fingerprint, entry]) => [
377
+ fingerprint,
378
+ { ...entry }
379
+ ])
380
+ )
381
+ } : void 0,
382
+ lastTurnReport: happyOrg?.lastTurnReport ? { ...happyOrg.lastTurnReport } : void 0
383
+ };
384
+ }
385
+ function normalizeHappyOrgMetadata(metadata) {
386
+ const happyOrg = cloneHappyOrgMetadata(metadata?.happyOrg);
387
+ return {
388
+ ...happyOrg,
389
+ runtime: happyOrg.runtime ?? {
390
+ status: "active",
391
+ reason: null
392
+ },
393
+ repeat: happyOrg.repeat ?? {
394
+ threshold: HAPPY_ORG_REPEAT_THRESHOLD,
395
+ fingerprints: {}
396
+ }
397
+ };
398
+ }
399
+ function withHappyOrgMetadata(metadata, happyOrg) {
400
+ return {
401
+ ...metadata,
402
+ happyOrg
403
+ };
404
+ }
405
+ function resetHappyOrgRuntimeForTask(taskContext) {
406
+ return {
407
+ taskContext,
408
+ runtime: {
409
+ status: "active",
410
+ reason: null
411
+ },
412
+ activeOwner: null,
413
+ repeat: {
414
+ threshold: HAPPY_ORG_REPEAT_THRESHOLD,
415
+ fingerprints: {}
416
+ }
417
+ };
418
+ }
419
+ function buildTerminatedStatusMessage(taskId) {
420
+ return `Task ${taskId} is terminated. Reopen it with new context, a new decision, or a new resource before continuing.`;
421
+ }
422
+ function buildMemberBusyStatusMessage(memberAgentId, activeTaskId, nextTaskId) {
423
+ return `Member ${memberAgentId} is already busy with active task ${activeTaskId}. Reject task ${nextTaskId} without continuing token usage.`;
424
+ }
425
+ function buildOwnerConflictStatusMessage(taskId, ownerAgentId) {
426
+ return `Task ${taskId} is already active under owner ${ownerAgentId}. This turn must exit without continuing token usage.`;
427
+ }
428
+ function inferDraftTurnStatus(draft) {
429
+ if (draft?.turnStatus === "turn_update" || draft?.turnStatus === "task_complete") {
430
+ return draft.turnStatus;
431
+ }
432
+ return null;
433
+ }
434
+ function inferInterventionType(draft) {
435
+ if (draft?.interventionType === "none" || draft?.interventionType === "review_needed" || draft?.interventionType === "blocker" || draft?.interventionType === "decision_needed") {
436
+ return draft.interventionType;
437
+ }
438
+ if (normalizeOptionalText(draft?.decisionNeeded)) {
439
+ return "decision_needed";
440
+ }
441
+ if (normalizeOptionalText(draft?.blockerCode)) {
442
+ return "blocker";
443
+ }
444
+ return "none";
445
+ }
446
+ function buildFallbackSummary(text, turnStatus) {
447
+ const trimmed = text.trim();
448
+ if (trimmed) {
449
+ return trimmed.replace(/\s+/g, " ").slice(0, HAPPY_ORG_SUMMARY_MAX_LENGTH);
450
+ }
451
+ return turnStatus === "turn_aborted" ? "Turn aborted before completion." : "Turn completed without a textual summary.";
452
+ }
453
+ function normalizeTurnReportDraft(draft) {
454
+ return {
455
+ turnStatus: inferDraftTurnStatus(draft),
456
+ summary: normalizeSummaryText(draft?.summary),
457
+ interventionType: inferInterventionType(draft),
458
+ blockerCode: normalizeOptionalText(draft?.blockerCode),
459
+ decisionNeeded: normalizeOptionalText(draft?.decisionNeeded),
460
+ targetArtifact: normalizeOptionalText(draft?.targetArtifact)
461
+ };
462
+ }
463
+ function stripCodeFence(text) {
464
+ return text.replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/i, "").trim();
465
+ }
466
+ function extractTaggedTurnReport(text) {
467
+ const matcher = new RegExp(
468
+ `<${HAPPY_ORG_TURN_REPORT_TAG}>\\s*([\\s\\S]*?)\\s*</${HAPPY_ORG_TURN_REPORT_TAG}>`,
469
+ "gi"
470
+ );
471
+ let lastMatch = null;
472
+ for (let match = matcher.exec(text); match; match = matcher.exec(text)) {
473
+ lastMatch = match;
474
+ }
475
+ if (!lastMatch) {
476
+ return {
477
+ cleanedText: text.trim(),
478
+ draft: null
479
+ };
480
+ }
481
+ const rawBlock = stripCodeFence(lastMatch[1] ?? "");
482
+ let draft = null;
483
+ try {
484
+ const parsed = JSON.parse(rawBlock);
485
+ draft = {
486
+ turnStatus: normalizeOptionalText(parsed.turnStatus),
487
+ summary: normalizeSummaryText(parsed.summary),
488
+ interventionType: normalizeOptionalText(parsed.interventionType),
489
+ blockerCode: normalizeOptionalText(parsed.blockerCode),
490
+ decisionNeeded: normalizeOptionalText(parsed.decisionNeeded),
491
+ targetArtifact: normalizeOptionalText(parsed.targetArtifact)
492
+ };
493
+ } catch {
494
+ draft = null;
495
+ }
496
+ const cleanedText = `${text.slice(0, lastMatch.index)}${text.slice(lastMatch.index + lastMatch[0].length)}`.replace(/\n{3,}/g, "\n\n").trim();
497
+ return {
498
+ cleanedText,
499
+ draft
500
+ };
501
+ }
502
+ function buildRepeatFingerprint(context, blockerCode, targetArtifact) {
503
+ if (!blockerCode) {
504
+ return null;
505
+ }
506
+ return [
507
+ context.taskId,
508
+ context.memberAgentId,
509
+ blockerCode,
510
+ targetArtifact ?? ""
511
+ ].join("::");
512
+ }
513
+ function resolveReportedTurnStatus(transportTurnStatus, draft) {
514
+ if (transportTurnStatus === "turn_aborted") {
515
+ return "turn_aborted";
516
+ }
517
+ return draft.turnStatus === "task_complete" ? "task_complete" : "turn_update";
518
+ }
519
+ function buildRuntimeStateAfterTurn(report) {
520
+ if (report.turnStatus === "task_complete") {
521
+ return {
522
+ status: "waiting_close",
523
+ reason: "awaiting_ceo_close"
524
+ };
525
+ }
526
+ switch (report.interventionType) {
527
+ case "decision_needed":
528
+ return {
529
+ status: "waiting_decision",
530
+ reason: "awaiting_user_decision"
531
+ };
532
+ case "review_needed":
533
+ return {
534
+ status: "waiting_review",
535
+ reason: "awaiting_ceo_review"
536
+ };
537
+ case "blocker":
538
+ return {
539
+ status: "waiting_review",
540
+ reason: "awaiting_ceo_context"
541
+ };
542
+ default:
543
+ return {
544
+ status: "active",
545
+ reason: null
546
+ };
547
+ }
548
+ }
549
+ function buildHappyOrgTurnPrompt(prompt, turn) {
550
+ const reopenLines = turn.reopenContext ? [
551
+ "",
552
+ "This task was explicitly reopened for this turn with the following new inputs:",
553
+ turn.reopenContext.newContext ? `- newContext: ${turn.reopenContext.newContext}` : null,
554
+ turn.reopenContext.newDecision ? `- newDecision: ${turn.reopenContext.newDecision}` : null,
555
+ turn.reopenContext.newResource ? `- newResource: ${turn.reopenContext.newResource}` : null
556
+ ].filter(Boolean) : [];
557
+ const header = [
558
+ "[HAPPY_ORG_TASK_CONTEXT]",
559
+ `taskId=${turn.context.taskId}`,
560
+ `organizationId=${turn.context.organizationId}`,
561
+ `memberAgentId=${turn.context.memberAgentId}`,
562
+ `supervisorAgentId=${turn.context.supervisorAgentId}`,
563
+ "Stay on this exact task for the whole turn.",
564
+ "End your response with exactly one raw JSON block inside these tags and do not wrap it in a markdown code fence:",
565
+ `<${HAPPY_ORG_TURN_REPORT_TAG}>{"turnStatus":"turn_update","summary":"short task-board summary","interventionType":"none","blockerCode":null,"decisionNeeded":null,"targetArtifact":null}</${HAPPY_ORG_TURN_REPORT_TAG}>`,
566
+ "Allowed turnStatus values in the JSON block: turn_update, task_complete.",
567
+ "Allowed interventionType values: none, review_needed, blocker, decision_needed.",
568
+ "Use turnStatus=task_complete only when you believe the assigned task is finished and ready for CEO acceptance.",
569
+ "If turnStatus=task_complete, the task will wait for CEO close; do not treat it as automatically closed.",
570
+ "If turnStatus=task_complete, interventionType must be review_needed.",
571
+ `summary must fit on a one-line CEO card or task-board card: short, actionable, no long process logs, max ${HAPPY_ORG_SUMMARY_MAX_LENGTH} characters.`,
572
+ "Use blocker only for problems the organization may still solve internally.",
573
+ "Use decision_needed only when a CEO or user decision is required.",
574
+ "Use review_needed when supervisor review is needed but the work is not blocked.",
575
+ ...reopenLines,
576
+ "[/HAPPY_ORG_TASK_CONTEXT]",
577
+ "",
578
+ prompt
579
+ ];
580
+ return header.join("\n");
581
+ }
582
+ function resolveHappyOrgQueuedTurn(opts) {
583
+ const metadata = opts.metadata ?? null;
584
+ if (!metadata) {
585
+ return {
586
+ nextMetadata: null,
587
+ queuedTurn: null,
588
+ blocked: false
589
+ };
590
+ }
591
+ const currentHappyOrg = normalizeHappyOrgMetadata(metadata);
592
+ let nextHappyOrg = cloneHappyOrgMetadata(currentHappyOrg);
593
+ const messageHappyOrg = opts.message.meta?.happyOrg;
594
+ const now = opts.now?.() ?? Date.now();
595
+ const createRunId = opts.createRunId ?? ((taskContext2, currentNow) => `${taskContext2.taskId}:${taskContext2.memberAgentId}:${currentNow}`);
596
+ if (messageHappyOrg?.taskContext) {
597
+ const currentTaskId = currentHappyOrg.taskContext?.taskId ?? null;
598
+ if (currentTaskId !== messageHappyOrg.taskContext.taskId) {
599
+ if (currentHappyOrg.taskContext && currentHappyOrg.runtime?.status === "active") {
600
+ return {
601
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
602
+ queuedTurn: null,
603
+ blocked: true,
604
+ statusMessage: buildMemberBusyStatusMessage(
605
+ currentHappyOrg.taskContext.memberAgentId,
606
+ currentHappyOrg.taskContext.taskId,
607
+ messageHappyOrg.taskContext.taskId
608
+ )
609
+ };
610
+ }
611
+ nextHappyOrg = resetHappyOrgRuntimeForTask(messageHappyOrg.taskContext);
612
+ } else {
613
+ nextHappyOrg.taskContext = { ...messageHappyOrg.taskContext };
614
+ }
615
+ }
616
+ const taskContext = nextHappyOrg.taskContext ?? null;
617
+ if (!taskContext) {
618
+ return {
619
+ nextMetadata: metadata,
620
+ queuedTurn: null,
621
+ blocked: false
622
+ };
623
+ }
624
+ const control = messageHappyOrg?.control;
625
+ if (control?.action === "terminate") {
626
+ nextHappyOrg.runtime = {
627
+ status: "terminated",
628
+ reason: normalizeOptionalText(control.reason) ?? "terminated_by_supervisor",
629
+ terminatedAt: now
630
+ };
631
+ nextHappyOrg.activeOwner = null;
632
+ return {
633
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
634
+ queuedTurn: null,
635
+ blocked: true,
636
+ statusMessage: buildTerminatedStatusMessage(taskContext.taskId)
637
+ };
638
+ }
639
+ const hasReopenInputs = Boolean(
640
+ normalizeOptionalText(control?.newContext) || normalizeOptionalText(control?.newDecision) || normalizeOptionalText(control?.newResource)
641
+ );
642
+ if (nextHappyOrg.runtime?.status === "terminated") {
643
+ if (control?.action !== "reopen") {
644
+ return {
645
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
646
+ queuedTurn: null,
647
+ blocked: true,
648
+ statusMessage: buildTerminatedStatusMessage(taskContext.taskId)
649
+ };
650
+ }
651
+ if (!hasReopenInputs) {
652
+ return {
653
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
654
+ queuedTurn: null,
655
+ blocked: true,
656
+ statusMessage: `Task ${taskContext.taskId} can only reopen with new context, a new decision, or a new resource.`
657
+ };
658
+ }
659
+ }
660
+ const reopenContext = control?.action === "reopen" && hasReopenInputs ? {
661
+ newContext: normalizeOptionalText(control.newContext),
662
+ newDecision: normalizeOptionalText(control.newDecision),
663
+ newResource: normalizeOptionalText(control.newResource)
664
+ } : void 0;
665
+ if (reopenContext) {
666
+ nextHappyOrg.runtime = {
667
+ status: "active",
668
+ reason: null,
669
+ reopenedAt: now
670
+ };
671
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "active") {
672
+ nextHappyOrg.runtime = {
673
+ status: "active",
674
+ reason: null
675
+ };
676
+ }
677
+ if (!nextHappyOrg.activeOwner) {
678
+ nextHappyOrg.activeOwner = {
679
+ ownerAgentId: taskContext.memberAgentId,
680
+ ownerRunId: createRunId(taskContext, now),
681
+ claimedAt: now
682
+ };
683
+ } else if (nextHappyOrg.activeOwner.ownerAgentId !== taskContext.memberAgentId) {
684
+ return {
685
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
686
+ queuedTurn: null,
687
+ blocked: true,
688
+ statusMessage: buildOwnerConflictStatusMessage(
689
+ taskContext.taskId,
690
+ nextHappyOrg.activeOwner.ownerAgentId
691
+ )
692
+ };
693
+ }
694
+ return {
695
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
696
+ queuedTurn: {
697
+ context: taskContext,
698
+ ...reopenContext ? { reopenContext } : {}
699
+ },
700
+ blocked: false
701
+ };
702
+ }
703
+ function finalizeHappyOrgTurn(opts) {
704
+ const metadata = opts.metadata ?? null;
705
+ const queuedTurn = opts.queuedTurn ?? null;
706
+ const { cleanedText, draft } = extractTaggedTurnReport(opts.responseText);
707
+ if (!metadata || !queuedTurn) {
708
+ return {
709
+ cleanedText,
710
+ report: null,
711
+ nextMetadata: metadata
712
+ };
713
+ }
714
+ const now = opts.now?.() ?? Date.now();
715
+ const normalizedDraft = normalizeTurnReportDraft(draft);
716
+ const reportTurnStatus = resolveReportedTurnStatus(opts.turnStatus, normalizedDraft);
717
+ const report = {
718
+ ...queuedTurn.context,
719
+ turnStatus: reportTurnStatus,
720
+ interventionType: reportTurnStatus === "task_complete" ? "review_needed" : normalizedDraft.interventionType ?? "none",
721
+ summary: normalizedDraft.summary ?? buildFallbackSummary(cleanedText, reportTurnStatus),
722
+ blockerCode: normalizedDraft.blockerCode ?? null,
723
+ decisionNeeded: normalizedDraft.decisionNeeded ?? null,
724
+ targetArtifact: normalizedDraft.targetArtifact ?? null,
725
+ repeatFingerprint: buildRepeatFingerprint(
726
+ queuedTurn.context,
727
+ normalizedDraft.blockerCode ?? null,
728
+ normalizedDraft.targetArtifact ?? null
729
+ )
730
+ };
731
+ const nextHappyOrg = normalizeHappyOrgMetadata(metadata);
732
+ nextHappyOrg.taskContext = { ...queuedTurn.context };
733
+ nextHappyOrg.lastTurnReport = report;
734
+ nextHappyOrg.activeOwner = null;
735
+ nextHappyOrg.repeat = nextHappyOrg.repeat ?? {
736
+ threshold: HAPPY_ORG_REPEAT_THRESHOLD,
737
+ fingerprints: {}
738
+ };
739
+ let terminateMessage;
740
+ if (report.repeatFingerprint) {
741
+ const currentEntry = nextHappyOrg.repeat.fingerprints[report.repeatFingerprint] ?? {
742
+ count: 0};
743
+ const nextCount = currentEntry.count + 1;
744
+ nextHappyOrg.repeat.fingerprints[report.repeatFingerprint] = {
745
+ count: nextCount,
746
+ lastSeenAt: now
747
+ };
748
+ if (nextCount >= nextHappyOrg.repeat.threshold) {
749
+ nextHappyOrg.runtime = {
750
+ status: "terminated",
751
+ reason: `repeat_fingerprint:${report.repeatFingerprint}`,
752
+ terminatedAt: now
753
+ };
754
+ terminateMessage = `Task ${queuedTurn.context.taskId} hit repeat threshold for ${report.repeatFingerprint} and is now terminated until reopen.`;
755
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "terminated") {
756
+ nextHappyOrg.runtime = buildRuntimeStateAfterTurn(report);
757
+ }
758
+ } else if (!nextHappyOrg.runtime || nextHappyOrg.runtime.status !== "terminated") {
759
+ nextHappyOrg.runtime = buildRuntimeStateAfterTurn(report);
760
+ }
761
+ return {
762
+ cleanedText,
763
+ report,
764
+ nextMetadata: withHappyOrgMetadata(metadata, nextHappyOrg),
765
+ terminateMessage
766
+ };
767
+ }
768
+
354
769
  const DEFAULT_MAX_MESSAGES = 200;
355
770
  const DEFAULT_MAX_CHARACTERS = 1e5;
356
771
  const DEFAULT_MAX_MESSAGE_CHARACTERS = 8e3;
@@ -1176,4 +1591,4 @@ function registerKillSessionHandler(rpcHandlerManager, killThisHappy) {
1176
1591
  });
1177
1592
  }
1178
1593
 
1179
- export { BasePermissionHandler as B, ConversationHistory$1 as C, INTERACTION_SUPERSEDED_ERROR as I, MissingMachineIdError as M, INTERACTION_TIMED_OUT_ERROR as a, MessageQueue2 as b, createSessionMetadata as c, MessageBuffer as d, ensureManagedProviderMachine as e, closeProviderSession as f, getPendingInteractionTimeoutMs as g, hashObject as h, inferToolResultError as i, forwardAgentMessageToProviderSession as j, launchRuntimeHandleWithFactoryResult as l, registerKillSessionHandler as r, syncControlledByUserState as s, waitForResponseCompleteWithAbort as w };
1594
+ export { BasePermissionHandler as B, ConversationHistory$1 as C, INTERACTION_SUPERSEDED_ERROR as I, MissingMachineIdError as M, INTERACTION_TIMED_OUT_ERROR as a, MessageQueue2 as b, createSessionMetadata as c, registerKillSessionHandler as d, ensureManagedProviderMachine as e, MessageBuffer as f, getPendingInteractionTimeoutMs as g, hashObject as h, buildHappyOrgTurnPrompt as i, finalizeHappyOrgTurn as j, closeProviderSession as k, launchRuntimeHandleWithFactoryResult as l, inferToolResultError as m, forwardAgentMessageToProviderSession as n, resolveHappyOrgQueuedTurn as r, syncControlledByUserState as s, waitForResponseCompleteWithAbort as w };