@gajae-code/coding-agent 0.11.11 → 0.12.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 (182) hide show
  1. package/CHANGELOG.md +49 -3
  2. package/dist/types/cli/read-cli.d.ts +1 -0
  3. package/dist/types/commands/deep-interview.d.ts +9 -0
  4. package/dist/types/commands/harness.d.ts +22 -0
  5. package/dist/types/commands/read.d.ts +6 -0
  6. package/dist/types/config/model-registry.d.ts +4 -0
  7. package/dist/types/config/provider-auth-health.d.ts +14 -0
  8. package/dist/types/config/provider-ranking.d.ts +59 -0
  9. package/dist/types/config/settings-schema.d.ts +29 -1
  10. package/dist/types/config/settings.d.ts +2 -0
  11. package/dist/types/extensibility/extensions/types.d.ts +22 -2
  12. package/dist/types/extensibility/shared-events.d.ts +6 -0
  13. package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
  14. package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
  15. package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
  16. package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
  17. package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
  18. package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
  19. package/dist/types/gjc-runtime/ralplan-runtime.d.ts +52 -1
  20. package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
  21. package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
  22. package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
  23. package/dist/types/gjc-runtime/team-store.d.ts +12 -0
  24. package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
  25. package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +7 -0
  26. package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
  27. package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
  28. package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
  29. package/dist/types/main.d.ts +1 -1
  30. package/dist/types/memories/index.d.ts +2 -0
  31. package/dist/types/modes/acp/acp-agent.d.ts +8 -0
  32. package/dist/types/modes/components/assistant-message.d.ts +3 -1
  33. package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
  34. package/dist/types/modes/components/read-tool-group.d.ts +4 -4
  35. package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
  36. package/dist/types/modes/components/settings-selector.d.ts +2 -0
  37. package/dist/types/modes/components/tool-execution.d.ts +8 -0
  38. package/dist/types/modes/controllers/event-controller.d.ts +3 -0
  39. package/dist/types/modes/interactive-mode.d.ts +2 -0
  40. package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
  41. package/dist/types/modes/types.d.ts +2 -0
  42. package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
  43. package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
  44. package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
  45. package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
  46. package/dist/types/sdk/bus/index.d.ts +15 -1
  47. package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
  48. package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
  49. package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
  50. package/dist/types/sdk/host/control/operations.d.ts +1 -1
  51. package/dist/types/sdk/host/host.d.ts +2 -0
  52. package/dist/types/sdk/host/query/handlers.d.ts +5 -0
  53. package/dist/types/session/agent-session.d.ts +44 -10
  54. package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
  55. package/dist/types/session/session-manager.d.ts +25 -13
  56. package/dist/types/session/streaming-output.d.ts +60 -5
  57. package/dist/types/skill-state/active-state.d.ts +0 -4
  58. package/dist/types/skill-state/workflow-hud.d.ts +3 -0
  59. package/dist/types/tools/browser/launch.d.ts +7 -0
  60. package/dist/types/tools/fetch.d.ts +17 -1
  61. package/dist/types/tools/output-meta.d.ts +21 -1
  62. package/dist/types/tools/read-internals.d.ts +12 -0
  63. package/dist/types/tools/read.d.ts +45 -1
  64. package/dist/types/tools/resource-gc.d.ts +4 -0
  65. package/dist/types/tools/tool-result.d.ts +7 -1
  66. package/package.json +9 -13
  67. package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
  68. package/scripts/capture-sticky-viewport-showcase.ts +292 -0
  69. package/scripts/generate-sdk-operation-inventory.ts +2 -0
  70. package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
  71. package/scripts/verify-sticky-viewport-showcase.ts +611 -0
  72. package/src/capability/index.ts +8 -0
  73. package/src/cli/read-cli.ts +2 -1
  74. package/src/cli.ts +1 -0
  75. package/src/commands/deep-interview.ts +29 -9
  76. package/src/commands/harness.ts +35 -12
  77. package/src/commands/read.ts +11 -2
  78. package/src/commands/team.ts +1 -1
  79. package/src/config/model-registry.ts +21 -2
  80. package/src/config/provider-auth-health.ts +42 -0
  81. package/src/config/provider-ranking.ts +119 -0
  82. package/src/config/settings-schema.ts +23 -1
  83. package/src/config/settings.ts +246 -108
  84. package/src/defaults/gjc/skills/deep-interview/SKILL.md +229 -82
  85. package/src/defaults/gjc/skills/ralplan/SKILL.md +58 -25
  86. package/src/defaults/gjc/skills/team/SKILL.md +1 -1
  87. package/src/defaults/gjc/skills/ultragoal/SKILL.md +25 -15
  88. package/src/eval/py/executor.ts +7 -2
  89. package/src/extensibility/extensions/types.ts +28 -4
  90. package/src/extensibility/shared-events.ts +5 -0
  91. package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
  92. package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
  93. package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
  94. package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
  95. package/src/gjc-runtime/deep-interview-state.ts +12 -943
  96. package/src/gjc-runtime/gc-render.ts +1 -0
  97. package/src/gjc-runtime/gc-runtime.ts +11 -1
  98. package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
  99. package/src/gjc-runtime/ralplan-runtime.ts +742 -85
  100. package/src/gjc-runtime/state-runtime.ts +2 -1
  101. package/src/gjc-runtime/state-writer.ts +70 -222
  102. package/src/gjc-runtime/team-launch.ts +34 -5
  103. package/src/gjc-runtime/team-runtime.ts +970 -33
  104. package/src/gjc-runtime/team-store.ts +32 -0
  105. package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
  106. package/src/gjc-runtime/team-workers.ts +1 -0
  107. package/src/gjc-runtime/tmux-owner-isolation.ts +18 -0
  108. package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
  109. package/src/gjc-runtime/ultragoal-runtime.ts +13 -7
  110. package/src/gjc-runtime/workflow-manifest.generated.json +97 -350
  111. package/src/gjc-runtime/workflow-manifest.ts +34 -179
  112. package/src/hooks/native-skill-hook.ts +17 -4
  113. package/src/hooks/skill-state.ts +1 -23
  114. package/src/internal-urls/docs-index.generated.ts +8 -9
  115. package/src/internal-urls/local-root-gc.ts +127 -0
  116. package/src/main.ts +9 -5
  117. package/src/memories/index.ts +10 -0
  118. package/src/modes/DESIGN.md +47 -0
  119. package/src/modes/acp/acp-agent.ts +43 -7
  120. package/src/modes/acp/acp-event-mapper.ts +14 -7
  121. package/src/modes/acp/acp-mode.ts +39 -3
  122. package/src/modes/components/assistant-message.ts +123 -22
  123. package/src/modes/components/irc-sidebar.ts +176 -62
  124. package/src/modes/components/model-selector.ts +61 -4
  125. package/src/modes/components/oauth-selector.ts +42 -12
  126. package/src/modes/components/read-tool-group.ts +82 -14
  127. package/src/modes/components/session-observer-overlay.ts +187 -32
  128. package/src/modes/components/settings-selector.ts +60 -18
  129. package/src/modes/components/tool-execution.ts +138 -27
  130. package/src/modes/controllers/event-controller.ts +109 -27
  131. package/src/modes/controllers/extension-ui-controller.ts +19 -2
  132. package/src/modes/controllers/input-controller.ts +18 -3
  133. package/src/modes/controllers/selector-controller.ts +83 -37
  134. package/src/modes/interactive-mode.ts +62 -3
  135. package/src/modes/irc-observation-ledger.ts +71 -15
  136. package/src/modes/runtime-init.ts +19 -2
  137. package/src/modes/types.ts +2 -0
  138. package/src/modes/utils/ui-helpers.ts +94 -1
  139. package/src/prompts/agents/architect.md +9 -1
  140. package/src/prompts/agents/critic.md +9 -0
  141. package/src/prompts/system/system-prompt.md +0 -1
  142. package/src/prompts/tools/read.md +4 -2
  143. package/src/runtime-mcp/smithery-auth.ts +17 -2
  144. package/src/runtime-mcp/smithery-connect.ts +11 -1
  145. package/src/sdk/broker/lifecycle.ts +25 -6
  146. package/src/sdk/bus/control-drain-lease.ts +104 -0
  147. package/src/sdk/bus/index.ts +341 -38
  148. package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
  149. package/src/sdk/bus/prompt-reconciliation.ts +2 -1
  150. package/src/sdk/bus/reconciliation-store.ts +224 -0
  151. package/src/sdk/host/control/dispatch.ts +5 -1
  152. package/src/sdk/host/control/operations.ts +1 -1
  153. package/src/sdk/host/host.ts +23 -1
  154. package/src/sdk/host/query/handlers.ts +55 -0
  155. package/src/sdk/mcp/server.ts +46 -18
  156. package/src/sdk/protocol/operation-inventory.generated.json +29 -0
  157. package/src/sdk/protocol/operation-registry.ts +7 -2
  158. package/src/sdk/session.ts +13 -1
  159. package/src/session/agent-session.ts +466 -50
  160. package/src/session/memory-guard-checkpoint-participant.ts +131 -0
  161. package/src/session/session-manager.ts +764 -17
  162. package/src/session/streaming-output.ts +262 -43
  163. package/src/setup/provider-onboarding.ts +19 -4
  164. package/src/skill-state/active-state.ts +0 -10
  165. package/src/skill-state/workflow-hud.ts +25 -2
  166. package/src/skill-state/workflow-mutation-guard.ts +65 -7
  167. package/src/tools/ask.ts +89 -69
  168. package/src/tools/browser/launch.ts +41 -6
  169. package/src/tools/fetch.ts +114 -23
  170. package/src/tools/output-meta.ts +176 -9
  171. package/src/tools/path-utils.ts +5 -1
  172. package/src/tools/read-internals.ts +44 -0
  173. package/src/tools/read.ts +1542 -310
  174. package/src/tools/resource-gc.ts +182 -18
  175. package/src/tools/tool-result.ts +14 -1
  176. package/src/web/search/providers/codex.ts +1 -1
  177. package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
  178. package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
  179. package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
  180. package/src/gjc-runtime/deep-interview-draft.ts +0 -843
  181. package/src/gjc-runtime/deep-interview-payload.ts +0 -262
  182. package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
@@ -18,9 +18,15 @@ function safeProbeWindowsJobMemory(): WindowsJobMemoryProbeResult {
18
18
 
19
19
  import { logger } from "@gajae-code/utils";
20
20
  import type { Settings } from "../config/settings";
21
+ import { executeGjcTeamApiOperation, listGjcTeams, readGjcWorkerHeartbeat } from "../gjc-runtime/team-runtime";
21
22
  import { computeMemoryGuardDomain } from "../runtime/memory-domain";
22
- import { chooseMemoryGuardAction, MemoryGuardHost, resolveMemoryGuardPolicy } from "../runtime/memory-guard";
23
- import type { MemoryGuardPolicy } from "../runtime/memory-guard-contract";
23
+ import {
24
+ chooseMemoryGuardAction,
25
+ MemoryGuardHost,
26
+ resolveMemoryGuardPolicy,
27
+ revalidateMemoryGuardAction,
28
+ } from "../runtime/memory-guard";
29
+ import type { MemoryGuardPolicy, MemoryGuardWorkerSample } from "../runtime/memory-guard-contract";
24
30
  import { resolveEffectiveMemoryLimit } from "../runtime/memory-limit";
25
31
  import { listTabsForGc, releaseTabIfGcEligible, type TabGcSnapshot } from "./browser/tab-supervisor";
26
32
  import { cleanupStaleScreenshotFallbackDirs, hasCreatedScreenshotFallbackDir } from "./computer-gc";
@@ -85,6 +91,14 @@ export interface ResourceGcDeps {
85
91
  releaseTab: (name: string, policy: { now: () => number; idleMs: number }) => Promise<boolean>;
86
92
  cleanupScreenshots: (opts: { now: () => number; staleMs: number }) => Promise<{ scanned: number; removed: number }>;
87
93
  screenshotArmed: () => boolean;
94
+ listTeamWorkers?: (cwd: string, sessionId: string) => Promise<MemoryGuardWorkerSample[]>;
95
+ applyTeamWorkerGuard?: (
96
+ cwd: string,
97
+ sessionId: string,
98
+ workerId: string,
99
+ excessBytes: number,
100
+ incidentId: string,
101
+ ) => Promise<void>;
88
102
  }
89
103
 
90
104
  const defaultDeps: ResourceGcDeps = {
@@ -98,10 +112,13 @@ const defaultDeps: ResourceGcDeps = {
98
112
  releaseTab: (name, policy) => releaseTabIfGcEligible(name, policy),
99
113
  cleanupScreenshots: opts => cleanupStaleScreenshotFallbackDirs(opts),
100
114
  screenshotArmed: () => hasCreatedScreenshotFallbackDir(),
115
+ listTeamWorkers: (cwd, sessionId) => sampleTeamWorkers(cwd, sessionId),
116
+ applyTeamWorkerGuard: (cwd, sessionId, workerId, excessBytes, incidentId) =>
117
+ applySelectedTeamWorker(cwd, sessionId, workerId, excessBytes, incidentId),
101
118
  };
102
119
 
103
120
  // ── Controller state (process-global; tabs/browsers are module-global too) ──────────────────
104
- const activeSessions = new Map<string, Settings>();
121
+ const activeSessions = new Map<string, { settings: Settings; cwd: () => string }>();
105
122
  const scheduler = new MemoryGuardHost({
106
123
  run: async () => {
107
124
  await sweepOnce(deps);
@@ -114,11 +131,13 @@ const memoryGuardGcActive = new Set<string>();
114
131
  const memoryGuardLastEvaluatedAt = new Map<string, number>();
115
132
  const memoryGuardRestartAboveSince = new Map<string, number>();
116
133
  const memoryGuardRestartCooldownUntil = new Map<string, number>();
134
+ const memoryGuardWorkerIncidentIds = new Map<string, string>();
117
135
  let deps: ResourceGcDeps = defaultDeps;
118
136
 
119
137
  export interface ResourceGcRegistration {
120
138
  sessionId: string;
121
139
  settings: Settings;
140
+ cwd?: string | (() => string);
122
141
  }
123
142
 
124
143
  function resolveSessionSweepIntervalMs(settings: Settings): number {
@@ -134,7 +153,9 @@ function resolveSessionSweepIntervalMs(settings: Settings): number {
134
153
  * session unregisters.
135
154
  */
136
155
  export function registerResourceGcSession(reg: ResourceGcRegistration): () => void {
137
- activeSessions.set(reg.sessionId, reg.settings);
156
+ const registeredCwd = reg.cwd;
157
+ const cwd = typeof registeredCwd === "function" ? registeredCwd : () => registeredCwd ?? process.cwd();
158
+ activeSessions.set(reg.sessionId, { settings: reg.settings, cwd });
138
159
  const unregisterSchedule = scheduler.register({
139
160
  ownerId: reg.sessionId,
140
161
  intervalMs: resolveSessionSweepIntervalMs(reg.settings),
@@ -149,6 +170,7 @@ export function registerResourceGcSession(reg: ResourceGcRegistration): () => vo
149
170
  if (path === "memoryGuard.enabled" && !resolveMemoryGuardPolicy(reg.settings).enabled) {
150
171
  memoryGuardGcActive.delete(reg.sessionId);
151
172
  memoryGuardRestartAboveSince.delete(reg.sessionId);
173
+ memoryGuardWorkerIncidentIds.delete(reg.sessionId);
152
174
  memoryGuardRestartCooldownUntil.delete(reg.sessionId);
153
175
  memoryGuardLastEvaluatedAt.delete(reg.sessionId);
154
176
  }
@@ -162,6 +184,7 @@ export function registerResourceGcSession(reg: ResourceGcRegistration): () => vo
162
184
  memoryGuardLastEvaluatedAt.delete(reg.sessionId);
163
185
  memoryGuardGcActive.delete(reg.sessionId);
164
186
  memoryGuardRestartAboveSince.delete(reg.sessionId);
187
+ memoryGuardWorkerIncidentIds.delete(reg.sessionId);
165
188
  memoryGuardRestartCooldownUntil.delete(reg.sessionId);
166
189
  unregisterSchedule();
167
190
  unregisterSettings();
@@ -479,13 +502,14 @@ export function __selectMemoryPressureDomainForTest(
479
502
 
480
503
  function sweepMemoryPressureGuard(d: ResourceGcDeps): Promise<void> | undefined {
481
504
  let enabled = false;
482
- for (const [sessionId, settings] of activeSessions) {
505
+ for (const [sessionId, { settings }] of activeSessions) {
483
506
  if (resolveMemoryGuardPolicy(settings).enabled) {
484
507
  enabled = true;
485
508
  continue;
486
509
  }
487
510
  memoryGuardGcActive.delete(sessionId);
488
511
  memoryGuardRestartAboveSince.delete(sessionId);
512
+ memoryGuardWorkerIncidentIds.delete(sessionId);
489
513
  memoryGuardRestartCooldownUntil.delete(sessionId);
490
514
  memoryGuardLastEvaluatedAt.delete(sessionId);
491
515
  }
@@ -493,14 +517,107 @@ function sweepMemoryPressureGuard(d: ResourceGcDeps): Promise<void> | undefined
493
517
  return sweepEnabledMemoryPressureGuard(d);
494
518
  }
495
519
 
520
+ async function readLinuxWorkerRssBytes(pid: number): Promise<number | null> {
521
+ if (process.platform !== "linux" || !Number.isSafeInteger(pid) || pid <= 0) return null;
522
+ try {
523
+ const status = await Bun.file(`/proc/${pid}/status`).text();
524
+ const match = /^VmRSS:\s+(\d+)\s+kB$/m.exec(status);
525
+ if (!match) return null;
526
+ const kibibytes = Number(match[1]);
527
+ return Number.isSafeInteger(kibibytes) ? kibibytes * 1024 : null;
528
+ } catch {
529
+ return null;
530
+ }
531
+ }
532
+
533
+ async function readLinuxProcessStartTime(pid: number): Promise<string | null> {
534
+ try {
535
+ const stat = await Bun.file(`/proc/${pid}/stat`).text();
536
+ const commandEnd = stat.lastIndexOf(")");
537
+ if (commandEnd < 0) return null;
538
+ const startTime = stat
539
+ .slice(commandEnd + 2)
540
+ .trim()
541
+ .split(/\s+/)[19];
542
+ return startTime && /^\d+$/.test(startTime) ? startTime : null;
543
+ } catch {
544
+ return null;
545
+ }
546
+ }
547
+
548
+ async function sampleTeamWorkers(cwd: string, sessionId: string): Promise<MemoryGuardWorkerSample[]> {
549
+ if (process.platform !== "linux") return [];
550
+ const samples: MemoryGuardWorkerSample[] = [];
551
+ for (const team of await listGjcTeams(cwd, { ...process.env, GJC_SESSION_ID: sessionId })) {
552
+ if (team.phase === "complete" || team.phase === "cancelled") continue;
553
+ for (const worker of team.workers) {
554
+ try {
555
+ const heartbeat = await readGjcWorkerHeartbeat(team.team_name, worker.id, cwd, {
556
+ ...process.env,
557
+ GJC_SESSION_ID: sessionId,
558
+ });
559
+ const heartbeatAt = Date.parse(heartbeat?.last_turn_at ?? "");
560
+ if (
561
+ !heartbeat?.alive ||
562
+ !heartbeat.process_start_time ||
563
+ !Number.isFinite(heartbeatAt) ||
564
+ Date.now() - heartbeatAt >= 120_000 ||
565
+ (await readLinuxProcessStartTime(heartbeat.pid)) !== heartbeat.process_start_time
566
+ )
567
+ continue;
568
+ const guard = (await executeGjcTeamApiOperation(
569
+ "read-worker-memory-guard",
570
+ { team_name: team.team_name, worker: worker.id, platform: process.platform },
571
+ cwd,
572
+ { ...process.env, GJC_SESSION_ID: sessionId },
573
+ )) as { automatic_action_allowed?: boolean; state?: string };
574
+ if (!guard.automatic_action_allowed || guard.state === "blocked") continue;
575
+ const bytes = await readLinuxWorkerRssBytes(heartbeat.pid);
576
+ if (bytes === null) continue;
577
+ samples.push({ workerId: `${team.team_name}/${worker.id}`, bytes, accepted: true });
578
+ } catch {
579
+ // Missing or malformed worker authority is not eligible for automatic mutation.
580
+ }
581
+ }
582
+ }
583
+ return samples;
584
+ }
585
+
586
+ async function applySelectedTeamWorker(
587
+ cwd: string,
588
+ sessionId: string,
589
+ workerId: string,
590
+ excessBytes: number,
591
+ incidentId: string,
592
+ ): Promise<void> {
593
+ const separator = workerId.lastIndexOf("/");
594
+ if (separator <= 0 || separator === workerId.length - 1) return;
595
+ const teamName = workerId.slice(0, separator);
596
+ const worker = workerId.slice(separator + 1);
597
+ await executeGjcTeamApiOperation(
598
+ "apply-worker-memory-guard",
599
+ {
600
+ team_name: teamName,
601
+ worker,
602
+ platform: process.platform,
603
+ reason: "production_memory_pressure_sweep",
604
+ incident_id: incidentId,
605
+ candidates: [{ worker_id: worker, platform: process.platform, excess_bytes: excessBytes }],
606
+ },
607
+ cwd,
608
+ { ...process.env, GJC_SESSION_ID: sessionId },
609
+ );
610
+ }
496
611
  async function sweepEnabledMemoryPressureGuard(d: ResourceGcDeps): Promise<void> {
497
612
  const now = d.monotonicNow();
498
- const dueSessions: Array<{ sessionId: string; policy: MemoryGuardPolicy }> = [];
499
- for (const [sessionId, settings] of activeSessions) {
613
+ const dueSessions: Array<{ sessionId: string; policy: MemoryGuardPolicy; cwd: string }> = [];
614
+ for (const [sessionId, { settings, cwd: resolveCwd }] of activeSessions) {
500
615
  const policy = resolveMemoryGuardPolicy(settings);
616
+ const cwd = resolveCwd();
501
617
  if (!policy.enabled) {
502
618
  memoryGuardGcActive.delete(sessionId);
503
619
  memoryGuardRestartAboveSince.delete(sessionId);
620
+ memoryGuardWorkerIncidentIds.delete(sessionId);
504
621
  memoryGuardRestartCooldownUntil.delete(sessionId);
505
622
  memoryGuardLastEvaluatedAt.delete(sessionId);
506
623
  continue;
@@ -508,14 +625,15 @@ async function sweepEnabledMemoryPressureGuard(d: ResourceGcDeps): Promise<void>
508
625
  const lastEvaluated = memoryGuardLastEvaluatedAt.get(sessionId);
509
626
  if (lastEvaluated !== undefined && now - lastEvaluated < policy.checkIntervalMs) continue;
510
627
  memoryGuardLastEvaluatedAt.set(sessionId, now);
511
- dueSessions.push({ sessionId, policy });
628
+ dueSessions.push({ sessionId, policy, cwd });
512
629
  }
513
630
  if (dueSessions.length === 0) return;
514
631
 
515
632
  const snapshot = await d.memorySnapshot();
516
633
  let gcRequested = false;
517
634
  const gcTelemetry: Array<{ sessionId: string } & Record<string, unknown>> = [];
518
- for (const { sessionId, policy } of dueSessions) {
635
+ let workerActionTaken = false;
636
+ for (const { sessionId, policy, cwd } of dueSessions) {
519
637
  const pressure = __selectMemoryPressureDomainForTest(snapshot, policy.policyLimitBytes);
520
638
  const limit = resolveEffectiveMemoryLimit({
521
639
  hardCapBytes: pressure.hardCapBytes,
@@ -524,20 +642,23 @@ async function sweepEnabledMemoryPressureGuard(d: ResourceGcDeps): Promise<void>
524
642
  if (limit.effectiveBytes === null) {
525
643
  memoryGuardGcActive.delete(sessionId);
526
644
  memoryGuardRestartAboveSince.delete(sessionId);
645
+ memoryGuardWorkerIncidentIds.delete(sessionId);
527
646
  memoryGuardRestartCooldownUntil.delete(sessionId);
528
647
  continue;
529
648
  }
649
+ const workerSamples = await (d.listTeamWorkers ?? (async () => []))(cwd, sessionId);
530
650
  const domain = computeMemoryGuardDomain({
531
651
  effectiveLimitBytes: limit.effectiveBytes,
532
652
  totalUsageBytes: pressure.totalUsageBytes,
533
653
  parentBytes: pressure.parentBytes,
534
654
  parentReserveBytes: policy.parentReserveBytes,
535
- workers: [],
655
+ workers: workerSamples,
536
656
  });
537
657
  const decision = chooseMemoryGuardAction({
538
658
  domain,
539
659
  hostSupported: false,
540
- workerSupported: () => false,
660
+ workerSupported: workerId =>
661
+ workerSamples.some(worker => worker.workerId === workerId && worker.accepted !== false),
541
662
  });
542
663
  const usageRatio = pressure.totalUsageBytes / limit.effectiveBytes;
543
664
  if (usageRatio >= policy.gcThresholdRatio) {
@@ -560,17 +681,57 @@ async function sweepEnabledMemoryPressureGuard(d: ResourceGcDeps): Promise<void>
560
681
 
561
682
  if (usageRatio < policy.restartThresholdRatio) {
562
683
  memoryGuardRestartAboveSince.delete(sessionId);
684
+ memoryGuardWorkerIncidentIds.delete(sessionId);
563
685
  continue;
564
686
  }
565
687
  const aboveSince = memoryGuardRestartAboveSince.get(sessionId);
566
688
  if (aboveSince === undefined) {
567
689
  memoryGuardRestartAboveSince.set(sessionId, now);
690
+ memoryGuardWorkerIncidentIds.set(sessionId, `worker-pressure:${sessionId}:${Math.trunc(now)}`);
568
691
  continue;
569
692
  }
570
693
  const cooldownUntil = memoryGuardRestartCooldownUntil.get(sessionId) ?? 0;
571
694
  if (now - aboveSince < policy.restartThresholdWindowMs || now < cooldownUntil) continue;
572
- memoryGuardRestartCooldownUntil.set(sessionId, now + policy.cooldownMs);
573
- d.logWarn("Memory guard: restart threshold sustained; restart remains advisory-only", {
695
+ const workerIncidentId =
696
+ memoryGuardWorkerIncidentIds.get(sessionId) ?? `worker-pressure:${sessionId}:${Math.trunc(aboveSince)}`;
697
+ let workerActionAttemptedForSession = false;
698
+ if (decision.kind === "execute" && decision.target.kind === "worker" && !workerActionTaken) {
699
+ const refreshedWorkers = await (d.listTeamWorkers ?? (async () => []))(cwd, sessionId);
700
+ const refreshedDomain = computeMemoryGuardDomain({
701
+ effectiveLimitBytes: limit.effectiveBytes,
702
+ totalUsageBytes: pressure.totalUsageBytes,
703
+ parentBytes: pressure.parentBytes,
704
+ parentReserveBytes: policy.parentReserveBytes,
705
+ workers: refreshedWorkers,
706
+ });
707
+ const refreshedDecision = chooseMemoryGuardAction({
708
+ domain: refreshedDomain,
709
+ hostSupported: false,
710
+ workerSupported: workerId =>
711
+ refreshedWorkers.some(worker => worker.workerId === workerId && worker.accepted !== false),
712
+ });
713
+ const revalidated = revalidateMemoryGuardAction(decision, refreshedDecision);
714
+ if (revalidated.kind !== "execute" || revalidated.target.kind !== "worker") continue;
715
+ workerActionTaken = true;
716
+ workerActionAttemptedForSession = true;
717
+ try {
718
+ await (d.applyTeamWorkerGuard ?? (async () => undefined))(
719
+ cwd,
720
+ sessionId,
721
+ revalidated.target.workerId,
722
+ revalidated.target.excessBytes,
723
+ workerIncidentId,
724
+ );
725
+ } catch (error) {
726
+ d.logWarn("Memory guard: team worker action failed; continuing sweep", {
727
+ sessionId,
728
+ workerId: revalidated.target.workerId,
729
+ error: String(error),
730
+ });
731
+ }
732
+ }
733
+ if (workerActionAttemptedForSession) memoryGuardRestartCooldownUntil.set(sessionId, now + policy.cooldownMs);
734
+ d.logWarn("Memory guard: restart threshold sustained", {
574
735
  sessionId,
575
736
  parentBytes: pressure.parentBytes,
576
737
  totalUsageBytes: pressure.totalUsageBytes,
@@ -598,9 +759,9 @@ async function sweepEnabledMemoryPressureGuard(d: ResourceGcDeps): Promise<void>
598
759
 
599
760
  function ownerBrowserPolicy(snapshot: TabGcSnapshot): BrowserGcPolicy | null {
600
761
  if (!snapshot.ownerId) return null;
601
- const settings = activeSessions.get(snapshot.ownerId);
602
- if (!settings) return null;
603
- return resolveBrowserGcPolicy(settings);
762
+ const registration = activeSessions.get(snapshot.ownerId);
763
+ if (!registration) return null;
764
+ return resolveBrowserGcPolicy(registration.settings);
604
765
  }
605
766
 
606
767
  /** Coarse, ordering-only eligibility; the live recheck in releaseTabIfGcEligible is authoritative. */
@@ -639,7 +800,7 @@ async function sweepBrowserTabs(d: ResourceGcDeps): Promise<void> {
639
800
  function pressuredOwnerIds(d: ResourceGcDeps): Set<string> {
640
801
  const rss = d.rssBytes();
641
802
  const owners = new Set<string>();
642
- for (const [sessionId, settings] of activeSessions) {
803
+ for (const [sessionId, { settings }] of activeSessions) {
643
804
  const policy = resolveBrowserGcPolicy(settings);
644
805
  if (policy.enabled && rss > policy.rssLimitBytes) owners.add(sessionId);
645
806
  }
@@ -678,7 +839,7 @@ async function sweepScreenshots(d: ResourceGcDeps): Promise<void> {
678
839
 
679
840
  let staleMs: number | null = null;
680
841
  let scanIntervalMs = Number.POSITIVE_INFINITY;
681
- for (const settings of activeSessions.values()) {
842
+ for (const { settings } of activeSessions.values()) {
682
843
  const policy = resolveComputerGcPolicy(settings);
683
844
  if (!policy.enabled) continue;
684
845
  staleMs = staleMs === null ? policy.staleMs : Math.min(staleMs, policy.staleMs);
@@ -698,6 +859,8 @@ export function __setResourceGcDepsForTest(overrides: Partial<ResourceGcDeps>):
698
859
  ...defaultDeps,
699
860
  ...overrides,
700
861
  monotonicNow: overrides.monotonicNow ?? overrides.now ?? defaultDeps.monotonicNow,
862
+ listTeamWorkers: overrides.listTeamWorkers ?? (async () => []),
863
+ applyTeamWorkerGuard: overrides.applyTeamWorkerGuard ?? (async () => undefined),
701
864
  };
702
865
  }
703
866
 
@@ -749,6 +912,7 @@ export function __resetResourceGcForTest(): void {
749
912
  rssWarningActive = false;
750
913
  memoryGuardGcActive.clear();
751
914
  memoryGuardRestartAboveSince.clear();
915
+ memoryGuardWorkerIncidentIds.clear();
752
916
  memoryGuardRestartCooldownUntil.clear();
753
917
  memoryGuardLastEvaluatedAt.clear();
754
918
  lastScreenshotScanAt = 0;
@@ -1,6 +1,6 @@
1
1
  import type { AgentToolResult } from "@gajae-code/agent-core";
2
2
  import type { ImageContent, TextContent } from "@gajae-code/ai";
3
- import type { OutputSummary, TruncationResult } from "../session/streaming-output";
3
+ import type { OutputSummary, ReadWindow, TruncationResult } from "../session/streaming-output";
4
4
  import type { OutputMeta, TruncationOptions, TruncationSummaryOptions, TruncationTextOptions } from "./output-meta";
5
5
  import { outputMeta } from "./output-meta";
6
6
 
@@ -32,6 +32,19 @@ export class ToolResultBuilder<TDetails extends DetailsWithMeta> {
32
32
  return this;
33
33
  }
34
34
 
35
+ truncationWindows(
36
+ windows: ReadWindow,
37
+ options?: {
38
+ artifactId?: string;
39
+ noticeOwner?: "body";
40
+ maxBytes?: number;
41
+ rangeBase?: "file" | "window";
42
+ },
43
+ ): this {
44
+ this.#meta.truncationWindows(windows, options);
45
+ return this;
46
+ }
47
+
35
48
  truncationFromSummary(summary: OutputSummary, options: TruncationSummaryOptions): this {
36
49
  this.#meta.truncationFromSummary(summary, options);
37
50
  return this;
@@ -36,7 +36,7 @@ const DEFAULT_INSTRUCTIONS =
36
36
  "You are a helpful assistant with web search capabilities. Search the web to answer the user's question accurately and cite your sources.";
37
37
 
38
38
  function getConfiguredModel(): string | undefined {
39
- const configuredModel = $env.PI_CODEX_WEB_SEARCH_MODEL?.trim();
39
+ const configuredModel = ($env.GJC_OPENAI_CODE_WEB_SEARCH_MODEL ?? $env.PI_CODEX_WEB_SEARCH_MODEL)?.trim();
40
40
  return configuredModel ? configuredModel : undefined;
41
41
  }
42
42
 
@@ -1,8 +0,0 @@
1
- import { type DeepInterviewDraftKind } from "./deep-interview-payload";
2
- export interface DeepInterviewDraftResult {
3
- status: number;
4
- stdout?: string;
5
- stderr?: string;
6
- }
7
- export declare function runDeepInterviewDraftCommand(input: readonly string[], cwd: string): Promise<DeepInterviewDraftResult>;
8
- export declare function runDeepInterviewDraftInternalConsumeCommand(draftId: string, expectedDraftRevision: number, kind: DeepInterviewDraftKind, cwd: string): Promise<DeepInterviewDraftResult>;
@@ -1,41 +0,0 @@
1
- import type { DeepInterviewRoundResultV1 } from "./deep-interview-state";
2
- export declare const DEEP_INTERVIEW_DRAFT_KINDS: readonly ["initialize-context", "confirm-topology", "record-answer", "apply-round-result"];
3
- export type DeepInterviewDraftKind = (typeof DEEP_INTERVIEW_DRAFT_KINDS)[number];
4
- export type DeepInterviewDraftPayload = Record<string, unknown>;
5
- export type DraftScalarType = "string" | "id" | "text" | "score" | "number" | "safe-int" | "boolean" | "enum";
6
- export interface DraftLeafDescriptor {
7
- kind: "leaf";
8
- type: DraftScalarType;
9
- nullable?: boolean;
10
- maxBytes?: number;
11
- values?: readonly string[];
12
- optional?: boolean;
13
- dynamicMapValue?: boolean;
14
- }
15
- export interface DraftObjectDescriptor {
16
- kind: "object";
17
- fields: Record<string, DraftDescriptor>;
18
- optional?: boolean;
19
- dynamicMapValue?: boolean;
20
- dynamicValue?: DraftLeafDescriptor;
21
- }
22
- export interface DraftArrayDescriptor {
23
- kind: "array";
24
- item: DraftLeafDescriptor | DraftObjectDescriptor;
25
- maxItems: number;
26
- optional?: boolean;
27
- }
28
- export type DraftDescriptor = DraftLeafDescriptor | DraftObjectDescriptor | DraftArrayDescriptor;
29
- export declare function deepInterviewDraftSchema(kind: DeepInterviewDraftKind): DraftObjectDescriptor;
30
- /** Shared strict payload decoders used by compatibility JSON and CLI-owned drafts. */
31
- export declare function decodeInitializeContextPayload(payload: unknown): Record<string, unknown>;
32
- export declare function decodeConfirmTopologyPayload(payload: unknown): Record<string, unknown>;
33
- export declare function decodeRecordAnswerPayload(payload: unknown): {
34
- question: string;
35
- answer: {
36
- selected_options: string[];
37
- custom_input: string | null;
38
- };
39
- };
40
- export declare function decodeApplyRoundResultPayload(payload: unknown, state: Record<string, unknown>): DeepInterviewRoundResultV1;
41
- export declare function validateDraftPayload(kind: DeepInterviewDraftKind, payload: unknown, state?: Record<string, unknown>): void;
@@ -1,17 +0,0 @@
1
- import { type DeepInterviewRoundResultV1 } from "./deep-interview-state";
2
- export interface DeepInterviewRepairResult {
3
- status: number;
4
- stdout?: string;
5
- stderr?: string;
6
- }
7
- export declare const DEEP_INTERVIEW_REPAIR_VERBS: readonly ["initialize-context", "confirm-topology", "record-answer", "apply-round-result", "inspect", "sanity-check"];
8
- export type DeepInterviewRepairVerb = (typeof DEEP_INTERVIEW_REPAIR_VERBS)[number];
9
- export declare function isDeepInterviewRepairVerb(value: string): value is DeepInterviewRepairVerb;
10
- export declare function decodeDeepInterviewAnswerJson(value: unknown): {
11
- selected_options: string[];
12
- custom_input: string | null;
13
- };
14
- export declare function decodeDeepInterviewRoundResultJson(value: unknown, state: Record<string, unknown>): DeepInterviewRoundResultV1;
15
- export declare function decodeDeepInterviewSetupJson(value: unknown): Record<string, unknown>;
16
- export declare function decodeDeepInterviewTopologyJson(value: unknown): Record<string, unknown>;
17
- export declare function runDeepInterviewRepairCommand(args: readonly string[], cwd: string): Promise<DeepInterviewRepairResult>;