@gajae-code/coding-agent 0.11.11 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +131 -4
- package/dist/types/async/job-manager.d.ts +17 -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 +83 -1
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +38 -4
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- 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/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/memory-guard-owner-claims.d.ts +47 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +70 -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 +27 -1
- package/dist/types/gjc-runtime/team-store.d.ts +12 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/team-worker-memory-guard.d.ts +92 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +17 -0
- package/dist/types/gjc-runtime/ultragoal-receipt-freshness.d.ts +8 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +31 -80
- 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 +10 -19
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +41 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/read-tool-group.d.ts +4 -4
- package/dist/types/modes/components/session-observer-overlay.d.ts +22 -0
- package/dist/types/modes/components/settings-selector.d.ts +11 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/tool-execution.d.ts +8 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- 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/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/runtime-mcp/smithery-auth.d.ts +5 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/lifecycle.d.ts +5 -0
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +4 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/control-drain-lease.d.ts +52 -0
- package/dist/types/sdk/bus/index.d.ts +44 -1
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +44 -0
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/prompt-reconciliation.d.ts +2 -1
- package/dist/types/sdk/bus/reconciliation-store.d.ts +69 -0
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +11 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- 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/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +82 -12
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +8 -1
- package/dist/types/session/memory-guard-checkpoint-participant.d.ts +69 -0
- package/dist/types/session/session-manager.d.ts +48 -19
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +96 -12
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -4
- package/dist/types/skill-state/workflow-hud.d.ts +9 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/browser/launch.d.ts +7 -0
- package/dist/types/tools/fetch.d.ts +17 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +4 -0
- package/dist/types/tools/output-meta.d.ts +44 -3
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read-internals.d.ts +12 -0
- package/dist/types/tools/read.d.ts +45 -7
- package/dist/types/tools/resource-gc.d.ts +4 -0
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/tools/tool-result.d.ts +7 -1
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +11 -13
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/benchmark-sticky-viewport-pr1.ts +239 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/capture-sticky-viewport-showcase.ts +292 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/scripts/verify-gjc-sdk-canonicalization.ts +122 -18
- package/scripts/verify-sticky-viewport-showcase.ts +611 -0
- package/src/async/job-manager.ts +78 -20
- package/src/capability/index.ts +8 -0
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- 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 +20 -2
- package/src/config/file-lock.ts +11 -2
- 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 +74 -1
- package/src/config/settings.ts +246 -108
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +230 -82
- package/src/defaults/gjc/skills/ralplan/SKILL.md +77 -41
- package/src/defaults/gjc/skills/team/SKILL.md +3 -1
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +62 -39
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/eval/py/executor.ts +7 -2
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +46 -5
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- 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/launch-tmux.ts +25 -6
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/memory-guard-owner-claims.ts +389 -0
- package/src/gjc-runtime/ralplan-runtime.ts +1149 -98
- 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 +42 -5
- package/src/gjc-runtime/team-runtime.ts +1085 -40
- package/src/gjc-runtime/team-store.ts +32 -0
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -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 +28 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-receipt-freshness.ts +20 -0
- package/src/gjc-runtime/ultragoal-runtime.ts +414 -618
- package/src/gjc-runtime/workflow-manifest.generated.json +105 -449
- package/src/gjc-runtime/workflow-manifest.ts +38 -247
- 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 +21 -22
- 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 +98 -0
- package/src/modes/acp/acp-agent.ts +339 -191
- 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/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +176 -62
- package/src/modes/components/model-selector.ts +61 -4
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +96 -28
- package/src/modes/components/read-tool-group.ts +82 -14
- package/src/modes/components/session-observer-overlay.ts +457 -83
- package/src/modes/components/settings-selector.ts +116 -23
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-execution.ts +138 -27
- package/src/modes/components/tool-status-header.ts +3 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/event-controller.ts +109 -27
- package/src/modes/controllers/extension-ui-controller.ts +26 -2
- package/src/modes/controllers/input-controller.ts +18 -3
- package/src/modes/controllers/selector-controller.ts +127 -36
- package/src/modes/interactive-mode.ts +62 -3
- package/src/modes/irc-observation-ledger.ts +71 -15
- package/src/modes/runtime-init.ts +22 -2
- package/src/modes/types.ts +2 -0
- package/src/modes/utils/ui-helpers.ts +94 -1
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/agents/architect.md +9 -1
- package/src/prompts/agents/critic.md +9 -0
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -5
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/read.md +4 -2
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/runtime-mcp/smithery-auth.ts +17 -2
- package/src/runtime-mcp/smithery-connect.ts +11 -1
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +25 -6
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +6 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/control-drain-lease.ts +104 -0
- package/src/sdk/bus/index.ts +984 -146
- package/src/sdk/bus/kind-aware-reconciliation.ts +317 -0
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/prompt-reconciliation.ts +2 -1
- package/src/sdk/bus/reconciliation-store.ts +303 -0
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +11 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -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/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/mcp/server.ts +46 -18
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +51 -0
- package/src/sdk/protocol/operation-registry.ts +7 -2
- package/src/sdk/session.ts +101 -10
- package/src/session/agent-session.ts +1286 -220
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/memory-guard-checkpoint-participant.ts +131 -0
- package/src/session/session-manager.ts +2364 -438
- package/src/session/session-storage.ts +9 -1
- package/src/session/streaming-output.ts +500 -111
- package/src/setup/credential-import.ts +75 -13
- package/src/setup/provider-onboarding.ts +19 -4
- package/src/skill-state/active-state.ts +32 -10
- package/src/skill-state/workflow-hud.ts +42 -2
- package/src/skill-state/workflow-mutation-guard.ts +560 -8
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +169 -118
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/browser/launch.ts +41 -6
- package/src/tools/fetch.ts +114 -23
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +4 -0
- package/src/tools/output-meta.ts +281 -20
- package/src/tools/path-utils.ts +8 -3
- package/src/tools/read-internals.ts +44 -0
- package/src/tools/read.ts +1560 -310
- package/src/tools/resource-gc.ts +182 -18
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/tools/tool-result.ts +14 -1
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/codex.ts +1 -1
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- 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/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- 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/gjc-runtime/ultragoal-pipeline.ts +0 -306
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/review.ts
CHANGED
|
@@ -188,15 +188,13 @@ export interface SubmitReviewDetails {
|
|
|
188
188
|
// Re-export types for external use
|
|
189
189
|
export type { ReportFindingDetails };
|
|
190
190
|
/**
|
|
191
|
-
*
|
|
192
|
-
* `ReviewFinding` shape
|
|
191
|
+
* Convert tool-side `ReportFindingDetails` into the numeric-priority
|
|
192
|
+
* `ReviewFinding` shape used by caller-owned reviewer payloads.
|
|
193
193
|
*
|
|
194
194
|
* The `report_finding` tool exposes `priority` as a string enum (`"P0".."P3"`)
|
|
195
|
-
* for ergonomics,
|
|
196
|
-
*
|
|
197
|
-
*
|
|
198
|
-
* that surfaces a finding is rejected with `findings.0.priority: expected
|
|
199
|
-
* number, received string`.
|
|
195
|
+
* for ergonomics, while reviewer schemas may explicitly declare numeric
|
|
196
|
+
* priorities. This pure conversion does not add findings to completion data;
|
|
197
|
+
* callers that include `findings` own both that field and its output schema.
|
|
200
198
|
*/
|
|
201
199
|
export function toReviewFinding(details: ReportFindingDetails): ReviewFinding {
|
|
202
200
|
return {
|
package/src/tools/search.ts
CHANGED
|
@@ -287,6 +287,7 @@ export class SearchTool implements AgentTool<typeof searchSchema, SearchToolDeta
|
|
|
287
287
|
rawPaths: resolvedPaths,
|
|
288
288
|
cwd: this.session.cwd,
|
|
289
289
|
getArtifactsDir: this.session.getArtifactsDir,
|
|
290
|
+
getAuthorizedArtifactsDirs: this.session.getAuthorizedArtifactsDirs,
|
|
290
291
|
internalUrlAction: "search",
|
|
291
292
|
trackImmutableSources: true,
|
|
292
293
|
surfaceExactFilePaths: true,
|
|
@@ -192,6 +192,9 @@ function renderSubagentSnapshotBody(
|
|
|
192
192
|
}
|
|
193
193
|
if (snapshot.description) lines.push(` ${theme.fg("dim", `Description: ${snapshot.description}`)}`);
|
|
194
194
|
if (snapshot.outputRef) lines.push(` ${theme.fg("dim", `Output: ${snapshot.outputRef}`)}`);
|
|
195
|
+
if (snapshot.setupFailureSummary) {
|
|
196
|
+
lines.push(` ${theme.fg("error", `Setup failure: ${snapshot.setupFailureSummary}`)}`);
|
|
197
|
+
}
|
|
195
198
|
if (snapshot.assignment) {
|
|
196
199
|
lines.push(` ${theme.fg("dim", "Assignment:")}`);
|
|
197
200
|
for (const al of snapshot.assignment.split("\n")) lines.push(` ${theme.fg("toolOutput", replaceTabs(al))}`);
|
|
@@ -312,8 +315,9 @@ export const subagentToolRenderer = {
|
|
|
312
315
|
);
|
|
313
316
|
}
|
|
314
317
|
|
|
315
|
-
snapshotSignatures ??= subagents.map(
|
|
316
|
-
|
|
318
|
+
snapshotSignatures ??= subagents.map(
|
|
319
|
+
snapshot =>
|
|
320
|
+
`${subagentAwaitRenderedStateSignature([snapshot], result.details)}:${snapshot.setupFailureSummary ?? ""}`,
|
|
317
321
|
);
|
|
318
322
|
subagents.forEach((snapshot, index) => {
|
|
319
323
|
// Fresh per-subagent status line (cheap), then a cached or dynamic body.
|
package/src/tools/subagent.ts
CHANGED
|
@@ -65,6 +65,8 @@ export interface SubagentSnapshot {
|
|
|
65
65
|
durationMs: number;
|
|
66
66
|
resultText?: string;
|
|
67
67
|
errorText?: string;
|
|
68
|
+
/** Safe setup failure cause retained from the executor launch path. */
|
|
69
|
+
setupFailureSummary?: string;
|
|
68
70
|
resultPreview?: string;
|
|
69
71
|
outputRef?: string;
|
|
70
72
|
truncated?: boolean;
|
|
@@ -603,6 +605,7 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
603
605
|
}
|
|
604
606
|
if (snapshot.description) lines.push(`Description: ${snapshot.description}`);
|
|
605
607
|
if (snapshot.outputRef) lines.push(`Output: ${snapshot.outputRef}`);
|
|
608
|
+
if (snapshot.setupFailureSummary) lines.push(`Setup failure: ${snapshot.setupFailureSummary}`);
|
|
606
609
|
if (snapshot.assignment) lines.push("Assignment:", "```", snapshot.assignment, "```");
|
|
607
610
|
if (snapshot.steerMessage) {
|
|
608
611
|
lines.push(`Steer (${snapshot.steerState ?? "queued"}):`, "```", snapshot.steerMessage, "```");
|
|
@@ -731,6 +734,9 @@ export class SubagentTool implements AgentTool<typeof subagentSchema, SubagentTo
|
|
|
731
734
|
truncated: output.truncated,
|
|
732
735
|
}
|
|
733
736
|
: {}),
|
|
737
|
+
...(job.setupFailureSummary
|
|
738
|
+
? { setupFailureSummary: sanitizeText(job.setupFailureSummary, RECEIPT_PREVIEW_WIDTH) }
|
|
739
|
+
: {}),
|
|
734
740
|
...(outputRef ? { outputRef } : {}),
|
|
735
741
|
...(runningTimeoutGuidance ? { guidance: runningTimeoutGuidance } : {}),
|
|
736
742
|
...this.#modelFields(record),
|
|
@@ -31,8 +31,10 @@ export class TelegramSendTool implements AgentTool<typeof telegramSendSchema, Te
|
|
|
31
31
|
readonly summary = "Send a workspace file to Telegram";
|
|
32
32
|
readonly loadMode = "discoverable";
|
|
33
33
|
readonly description =
|
|
34
|
-
"Send a file from the current workspace to the connected Telegram chat
|
|
35
|
-
"
|
|
34
|
+
"Send a file from the current workspace to the connected Telegram chat. Recognized images are converted to " +
|
|
35
|
+
"Telegram-compatible photos when possible, including WebP; other files are sent as documents with their MIME " +
|
|
36
|
+
"type preserved. The path must resolve (after following symlinks) to a regular file inside the project root; " +
|
|
37
|
+
"paths outside the workspace are rejected.";
|
|
36
38
|
readonly parameters = telegramSendSchema;
|
|
37
39
|
readonly strict = true;
|
|
38
40
|
|
|
@@ -109,6 +111,7 @@ export class TelegramSendTool implements AgentTool<typeof telegramSendSchema, Te
|
|
|
109
111
|
};
|
|
110
112
|
}
|
|
111
113
|
const abs = contained.path;
|
|
114
|
+
const mime = Bun.file(abs).type;
|
|
112
115
|
|
|
113
116
|
const sink = getTelegramFileSink(sessionId);
|
|
114
117
|
if (!sink) {
|
|
@@ -126,7 +129,7 @@ export class TelegramSendTool implements AgentTool<typeof telegramSendSchema, Te
|
|
|
126
129
|
};
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
const result = await sink({ path: abs, caption: params.caption });
|
|
132
|
+
const result = await sink({ path: abs, caption: params.caption, mime });
|
|
130
133
|
if (result.ok) {
|
|
131
134
|
return {
|
|
132
135
|
content: [{ type: "text", text: `Sent ${path.basename(abs)} to Telegram.` }],
|
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;
|
package/src/utils/gh.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const DEFAULT_GH_TIMEOUT_MS = 5_000;
|
|
2
|
+
|
|
3
|
+
export interface GhResult {
|
|
4
|
+
exitCode: number;
|
|
5
|
+
stdout: string;
|
|
6
|
+
stderr: string;
|
|
7
|
+
timedOut?: boolean;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type RunGh = (args: string[], options?: { timeoutMs?: number }) => Promise<GhResult>;
|
|
11
|
+
|
|
12
|
+
/** Run GitHub CLI without allowing it to consume the parent terminal's input. */
|
|
13
|
+
export async function runGhDefault(args: string[], options?: { timeoutMs?: number }): Promise<GhResult> {
|
|
14
|
+
const ghPath = Bun.which("gh");
|
|
15
|
+
if (!ghPath) {
|
|
16
|
+
return { exitCode: -1, stdout: "", stderr: "gh not found", timedOut: false };
|
|
17
|
+
}
|
|
18
|
+
const timeoutMs = options?.timeoutMs ?? DEFAULT_GH_TIMEOUT_MS;
|
|
19
|
+
let timedOut = false;
|
|
20
|
+
try {
|
|
21
|
+
const proc = Bun.spawn([ghPath, ...args], { stdout: "pipe", stderr: "pipe", stdin: "ignore" });
|
|
22
|
+
const timer = setTimeout(() => {
|
|
23
|
+
timedOut = true;
|
|
24
|
+
proc.kill();
|
|
25
|
+
}, timeoutMs);
|
|
26
|
+
try {
|
|
27
|
+
const [stdout, stderr] = await Promise.all([
|
|
28
|
+
new Response(proc.stdout).text(),
|
|
29
|
+
new Response(proc.stderr).text(),
|
|
30
|
+
]);
|
|
31
|
+
const exitCode = await proc.exited;
|
|
32
|
+
return { exitCode, stdout, stderr, timedOut };
|
|
33
|
+
} finally {
|
|
34
|
+
clearTimeout(timer);
|
|
35
|
+
}
|
|
36
|
+
} catch (err) {
|
|
37
|
+
return { exitCode: -1, stdout: "", stderr: err instanceof Error ? err.message : String(err), timedOut };
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -6,6 +6,7 @@ export interface ImageResizeOptions {
|
|
|
6
6
|
maxBytes?: number;
|
|
7
7
|
jpegQuality?: number;
|
|
8
8
|
excludeWebP?: boolean;
|
|
9
|
+
forceReencode?: boolean;
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export interface ResizedImage {
|
|
@@ -30,6 +31,7 @@ const DEFAULT_OPTIONS: Required<Omit<ImageResizeOptions, "excludeWebP">> = {
|
|
|
30
31
|
maxHeight: 1568,
|
|
31
32
|
maxBytes: DEFAULT_IMAGE_RESIZE_MAX_BYTES,
|
|
32
33
|
jpegQuality: 80,
|
|
34
|
+
forceReencode: false,
|
|
33
35
|
};
|
|
34
36
|
|
|
35
37
|
/**
|
|
@@ -94,6 +96,7 @@ export async function resizeImageBuffer(
|
|
|
94
96
|
originalWidth <= opts.maxWidth &&
|
|
95
97
|
originalHeight <= opts.maxHeight &&
|
|
96
98
|
originalSize <= comfortableSize &&
|
|
99
|
+
!opts.forceReencode &&
|
|
97
100
|
!(opts.excludeWebP && sourceMime === "image/webp")
|
|
98
101
|
) {
|
|
99
102
|
return {
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
buildAnthropicUrl,
|
|
15
15
|
stripClaudeToolPrefix,
|
|
16
16
|
} from "@gajae-code/ai";
|
|
17
|
-
import { $env } from "@gajae-code/utils";
|
|
17
|
+
import { $credentialEnv, $env } from "@gajae-code/utils";
|
|
18
18
|
import type {
|
|
19
19
|
AnthropicApiResponse,
|
|
20
20
|
AnthropicCitation,
|
|
@@ -275,8 +275,8 @@ export async function searchAnthropic(
|
|
|
275
275
|
params: SearchParams | AnthropicSearchParams,
|
|
276
276
|
_legacyStorage?: unknown,
|
|
277
277
|
): Promise<SearchResponse> {
|
|
278
|
-
const searchApiKey = $
|
|
279
|
-
const searchBaseUrl = $
|
|
278
|
+
const searchApiKey = $credentialEnv("ANTHROPIC_SEARCH_API_KEY");
|
|
279
|
+
const searchBaseUrl = $credentialEnv("ANTHROPIC_SEARCH_BASE_URL");
|
|
280
280
|
let auth: AnthropicAuthConfig | undefined;
|
|
281
281
|
// When reusing the active model's own credentials (native search over a
|
|
282
282
|
// proxy), prefer its wire model id and carry its request headers through.
|
|
@@ -360,7 +360,7 @@ export class AnthropicProvider extends SearchProvider {
|
|
|
360
360
|
readonly label = "Anthropic";
|
|
361
361
|
|
|
362
362
|
isAvailable(authStorage: AuthStorage): Promise<boolean> | boolean {
|
|
363
|
-
return Boolean($
|
|
363
|
+
return Boolean($credentialEnv("ANTHROPIC_SEARCH_API_KEY")) || authStorage.hasAuth("anthropic");
|
|
364
364
|
}
|
|
365
365
|
|
|
366
366
|
search(params: SearchParams): Promise<SearchResponse> {
|
|
@@ -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
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Endpoint: POST https://api.kimi.com/coding/v1/search
|
|
6
6
|
*/
|
|
7
7
|
import type { AuthStorage } from "@gajae-code/ai";
|
|
8
|
-
import { $
|
|
8
|
+
import { $credentialEnv } from "@gajae-code/utils";
|
|
9
9
|
|
|
10
10
|
import type { SearchResponse, SearchSource } from "../../../web/search/types";
|
|
11
11
|
import { SearchProviderError } from "../../../web/search/types";
|
|
@@ -55,8 +55,17 @@ function asTrimmed(value: string | undefined): string | undefined {
|
|
|
55
55
|
return trimmed.length > 0 ? trimmed : undefined;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
/** Test seam: the Kimi search base URL as resolved from trusted env. */
|
|
59
|
+
export function resolveKimiSearchBaseUrlForTest(): string {
|
|
60
|
+
return resolveBaseUrl();
|
|
61
|
+
}
|
|
62
|
+
|
|
58
63
|
function resolveBaseUrl(): string {
|
|
59
|
-
return
|
|
64
|
+
return (
|
|
65
|
+
asTrimmed($credentialEnv("MOONSHOT_SEARCH_BASE_URL")) ??
|
|
66
|
+
asTrimmed($credentialEnv("KIMI_SEARCH_BASE_URL")) ??
|
|
67
|
+
KIMI_SEARCH_URL
|
|
68
|
+
);
|
|
60
69
|
}
|
|
61
70
|
|
|
62
71
|
/** Find Kimi search credentials from environment or AuthStorage. */
|
|
@@ -65,7 +74,8 @@ async function findApiKey(
|
|
|
65
74
|
sessionId: string | undefined,
|
|
66
75
|
signal: AbortSignal | undefined,
|
|
67
76
|
): Promise<string | null> {
|
|
68
|
-
const envKey =
|
|
77
|
+
const envKey =
|
|
78
|
+
asTrimmed($credentialEnv("MOONSHOT_SEARCH_API_KEY")) ?? asTrimmed($credentialEnv("KIMI_SEARCH_API_KEY"));
|
|
69
79
|
if (envKey) return envKey;
|
|
70
80
|
|
|
71
81
|
return (
|
|
@@ -157,8 +167,8 @@ export class KimiProvider extends SearchProvider {
|
|
|
157
167
|
|
|
158
168
|
isAvailable(authStorage: AuthStorage): boolean {
|
|
159
169
|
return (
|
|
160
|
-
!!asTrimmed($
|
|
161
|
-
!!asTrimmed($
|
|
170
|
+
!!asTrimmed($credentialEnv("MOONSHOT_SEARCH_API_KEY")) ||
|
|
171
|
+
!!asTrimmed($credentialEnv("KIMI_SEARCH_API_KEY")) ||
|
|
162
172
|
authStorage.hasAuth("moonshot") ||
|
|
163
173
|
authStorage.hasAuth("kimi-code")
|
|
164
174
|
);
|