@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.
- package/CHANGELOG.md +49 -3
- package/dist/types/cli/read-cli.d.ts +1 -0
- package/dist/types/commands/deep-interview.d.ts +9 -0
- package/dist/types/commands/harness.d.ts +22 -0
- package/dist/types/commands/read.d.ts +6 -0
- package/dist/types/config/model-registry.d.ts +4 -0
- package/dist/types/config/provider-auth-health.d.ts +14 -0
- package/dist/types/config/provider-ranking.d.ts +59 -0
- package/dist/types/config/settings-schema.d.ts +29 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/extensibility/extensions/types.d.ts +22 -2
- package/dist/types/extensibility/shared-events.d.ts +6 -0
- package/dist/types/gjc-runtime/deep-interview-ambiguity.d.ts +5 -12
- package/dist/types/gjc-runtime/deep-interview-recorder.d.ts +17 -32
- package/dist/types/gjc-runtime/deep-interview-stage.d.ts +37 -0
- package/dist/types/gjc-runtime/deep-interview-state.d.ts +4 -135
- package/dist/types/gjc-runtime/gc-runtime.d.ts +1 -1
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +52 -1
- package/dist/types/gjc-runtime/state-writer.d.ts +5 -46
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +2 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +7 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +3 -5
- package/dist/types/internal-urls/local-root-gc.d.ts +2 -0
- package/dist/types/main.d.ts +1 -1
- package/dist/types/memories/index.d.ts +2 -0
- package/dist/types/modes/acp/acp-agent.d.ts +8 -0
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +4 -0
- package/dist/types/modes/components/settings-selector.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/controllers/event-controller.d.ts +3 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/irc-observation-ledger.d.ts +17 -1
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/modes/utils/ui-helpers.d.ts +16 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +15 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +37 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +65 -0
- package/dist/types/sdk/host/control/operations.d.ts +1 -1
- package/dist/types/sdk/host/host.d.ts +2 -0
- package/dist/types/sdk/host/query/handlers.d.ts +5 -0
- package/dist/types/session/agent-session.d.ts +44 -10
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +25 -13
- package/dist/types/session/streaming-output.d.ts +60 -5
- package/dist/types/skill-state/active-state.d.ts +0 -4
- package/dist/types/skill-state/workflow-hud.d.ts +3 -0
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/output-meta.d.ts +21 -1
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -1
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/package.json +9 -13
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +2 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/capability/index.ts +8 -0
- package/src/cli/read-cli.ts +2 -1
- package/src/cli.ts +1 -0
- package/src/commands/deep-interview.ts +29 -9
- package/src/commands/harness.ts +35 -12
- package/src/commands/read.ts +11 -2
- package/src/commands/team.ts +1 -1
- package/src/config/model-registry.ts +21 -2
- package/src/config/provider-auth-health.ts +42 -0
- package/src/config/provider-ranking.ts +119 -0
- package/src/config/settings-schema.ts +23 -1
- package/src/config/settings.ts +246 -108
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +229 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +58 -25
- package/src/defaults/gjc/skills/team/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +25 -15
- package/src/eval/py/executor.ts +7 -2
- package/src/extensibility/extensions/types.ts +28 -4
- package/src/extensibility/shared-events.ts +5 -0
- package/src/gjc-runtime/deep-interview-ambiguity.ts +47 -82
- package/src/gjc-runtime/deep-interview-recorder.ts +227 -310
- package/src/gjc-runtime/deep-interview-runtime.ts +109 -270
- package/src/gjc-runtime/deep-interview-stage.ts +1016 -0
- package/src/gjc-runtime/deep-interview-state.ts +12 -943
- package/src/gjc-runtime/gc-render.ts +1 -0
- package/src/gjc-runtime/gc-runtime.ts +11 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +742 -85
- package/src/gjc-runtime/state-runtime.ts +2 -1
- package/src/gjc-runtime/state-writer.ts +70 -222
- package/src/gjc-runtime/team-launch.ts +34 -5
- package/src/gjc-runtime/team-runtime.ts +970 -33
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-memory-guard.ts +363 -0
- package/src/gjc-runtime/team-workers.ts +1 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +18 -0
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +13 -7
- package/src/gjc-runtime/workflow-manifest.generated.json +97 -350
- package/src/gjc-runtime/workflow-manifest.ts +34 -179
- package/src/hooks/native-skill-hook.ts +17 -4
- package/src/hooks/skill-state.ts +1 -23
- package/src/internal-urls/docs-index.generated.ts +8 -9
- package/src/internal-urls/local-root-gc.ts +127 -0
- package/src/main.ts +9 -5
- package/src/memories/index.ts +10 -0
- package/src/modes/DESIGN.md +47 -0
- package/src/modes/acp/acp-agent.ts +43 -7
- package/src/modes/acp/acp-event-mapper.ts +14 -7
- package/src/modes/acp/acp-mode.ts +39 -3
- package/src/modes/components/assistant-message.ts +123 -22
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/oauth-selector.ts +42 -12
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +187 -32
- package/src/modes/components/settings-selector.ts +60 -18
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +19 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +83 -37
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +19 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/system-prompt.md +0 -1
- package/src/prompts/tools/read.md +4 -2
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +341 -38
- package/src/sdk/bus/kind-aware-reconciliation.ts +242 -0
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +224 -0
- package/src/sdk/host/control/dispatch.ts +5 -1
- package/src/sdk/host/control/operations.ts +1 -1
- package/src/sdk/host/host.ts +23 -1
- package/src/sdk/host/query/handlers.ts +55 -0
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/protocol/operation-inventory.generated.json +29 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +13 -1
- package/src/session/agent-session.ts +466 -50
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +764 -17
- package/src/session/streaming-output.ts +262 -43
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +0 -10
- package/src/skill-state/workflow-hud.ts +25 -2
- package/src/skill-state/workflow-mutation-guard.ts +65 -7
- package/src/tools/ask.ts +89 -69
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/output-meta.ts +176 -9
- package/src/tools/path-utils.ts +5 -1
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1542 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/tool-result.ts +14 -1
- package/src/web/search/providers/codex.ts +1 -1
- package/dist/types/gjc-runtime/deep-interview-draft.d.ts +0 -8
- package/dist/types/gjc-runtime/deep-interview-payload.d.ts +0 -41
- package/dist/types/gjc-runtime/deep-interview-repair.d.ts +0 -17
- package/src/gjc-runtime/deep-interview-draft.ts +0 -843
- package/src/gjc-runtime/deep-interview-payload.ts +0 -262
- package/src/gjc-runtime/deep-interview-repair.ts +0 -1674
package/src/tools/resource-gc.ts
CHANGED
|
@@ -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 {
|
|
23
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
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
|
-
|
|
573
|
-
|
|
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
|
|
602
|
-
if (!
|
|
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;
|
package/src/tools/tool-result.ts
CHANGED
|
@@ -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>;
|