triflux 10.44.0 → 10.46.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/README.md +1 -1
- package/adapters/codex/skills/tfx-harness/SKILL.md +45 -9
- package/bin/tfx-live.mjs +1298 -100
- package/bin/triflux.mjs +9 -6
- package/config/routing-policy.json +1 -1
- package/hooks/codex-session-hook.mjs +67 -1
- package/hooks/cto-north-star-brief.mjs +3 -16
- package/hooks/error-context.mjs +3 -6
- package/hooks/hook-manager.mjs +1 -1
- package/hooks/hook-registry.json +0 -11
- package/hooks/keyword-rules.json +8 -4
- package/hooks/permission-safe-allow.mjs +36 -2
- package/hooks/session-start-fast.mjs +50 -1
- package/hooks/session-start-lake.mjs +3 -16
- package/hub/bridge.mjs +111 -5
- package/hub/dynamic-routing-engine.mjs +1 -1
- package/hub/gemini-adapter.mjs +29 -11
- package/hub/lib/memory-store.mjs +66 -30
- package/hub/lib/tfx-route-args.mjs +41 -4
- package/hub/pipe.mjs +10 -15
- package/hub/reflexion.mjs +0 -57
- package/hub/router.mjs +202 -24
- package/hub/schema.sql +1 -0
- package/hub/server.mjs +172 -93
- package/hub/store.mjs +106 -33
- package/hub/team/backend.mjs +4 -2
- package/hub/team/claude-daemon-control.mjs +2 -0
- package/hub/team/cli/commands/start/start-headless.mjs +2 -0
- package/hub/team/cli/commands/start/start-mux.mjs +24 -3
- package/hub/team/cli/services/runtime-mode.mjs +23 -9
- package/hub/team/codex-review.mjs +2 -3
- package/hub/team/conductor.mjs +80 -24
- package/hub/team/cto-auto-collect.mjs +2 -6
- package/hub/team/cto-pull.mjs +4 -0
- package/hub/team/dashboard-open.mjs +1 -0
- package/hub/team/execution-mode.mjs +38 -2
- package/hub/team/headless.mjs +493 -82
- package/hub/team/interactive-tui-transport.mjs +15 -1
- package/hub/team/launcher-template.mjs +19 -2
- package/hub/team/orchestrator.mjs +36 -9
- package/hub/team/pane.mjs +176 -14
- package/hub/team/psmux.mjs +79 -70
- package/hub/team/retry-state-machine.mjs +47 -16
- package/hub/team/session.mjs +57 -0
- package/hub/team/terminal-opener.mjs +68 -13
- package/hub/team/tui-viewer.mjs +65 -14
- package/hub/team/uds-orchestrator.mjs +384 -83
- package/hub/tools.mjs +6 -0
- package/hub/workers/codex-mcp.mjs +35 -6
- package/hud/cli-policy.mjs +69 -0
- package/hud/constants.mjs +20 -17
- package/hud/context-monitor.mjs +31 -21
- package/hud/hud-qos-status.mjs +81 -91
- package/hud/providers/claude.mjs +150 -84
- package/hud/providers/codex.mjs +10 -1
- package/hud/renderers.mjs +21 -59
- package/hud/utils.mjs +1 -15
- package/package.json +1 -1
- package/scripts/__tests__/keyword-detector.test.mjs +89 -1
- package/scripts/__tests__/release-governance.test.mjs +329 -12
- package/scripts/__tests__/release-publish-ancestor.test.mjs +67 -0
- package/scripts/__tests__/release-verify-wait.test.mjs +169 -0
- package/scripts/__tests__/resolve-auto-release.test.mjs +216 -0
- package/scripts/__tests__/skill-surface.test.mjs +6 -4
- package/scripts/__tests__/tfx-route-bash-node-parity.test.mjs +7 -5
- package/scripts/__tests__/tfx-route-node-entry.test.mjs +27 -21
- package/scripts/claude-login-detect.mjs +107 -25
- package/scripts/ensure-agy-hooks.mjs +31 -1
- package/scripts/keyword-detector.mjs +11 -1
- package/scripts/lib/agent-route-policy.mjs +47 -39
- package/scripts/lib/cli-agy.mjs +24 -4
- package/scripts/lib/codex-profile-config.mjs +45 -13
- package/scripts/lib/codex-recovery.sh +19 -0
- package/scripts/lib/gemini-profiles.mjs +113 -29
- package/scripts/lib/keyword-rules.mjs +12 -0
- package/scripts/lib/logger.mjs +60 -43
- package/scripts/lib/machine-profile.mjs +293 -0
- package/scripts/lib/mcp-health.mjs +44 -18
- package/scripts/notion-read.mjs +2 -1
- package/scripts/release/check-packages-mirror.mjs +53 -1
- package/scripts/release/lib.mjs +1 -2
- package/scripts/release/prepare.mjs +24 -9
- package/scripts/release/publish.mjs +16 -1
- package/scripts/release/resolve-auto-release.mjs +136 -0
- package/scripts/release/verify.mjs +74 -25
- package/scripts/remote-spawn.mjs +830 -32
- package/scripts/session-stale-cleanup.mjs +0 -1
- package/scripts/setup.mjs +487 -150
- package/scripts/sync-hub-mcp-settings.mjs +11 -3
- package/scripts/test-lock.mjs +15 -1
- package/scripts/tfx-gate-activate.mjs +4 -4
- package/scripts/tfx-route-post.mjs +90 -13
- package/scripts/tfx-route.sh +520 -141
- package/skills/merge-worktree/SKILL.md +3 -3
- package/skills/star-prompt/skill.json +1 -1
- package/skills/tfx-analysis/SKILL.md +8 -9
- package/skills/tfx-analysis/skill.json +1 -10
- package/skills/tfx-auto/SKILL.md +208 -50
- package/skills/tfx-auto/skill.json +2 -23
- package/skills/tfx-doctor/skill.json +0 -3
- package/skills/tfx-find/skill.json +0 -7
- package/skills/tfx-forge/SKILL.md +2 -2
- package/skills/tfx-forge/skill.json +0 -7
- package/skills/tfx-goal-clarify/skill.json +5 -0
- package/skills/tfx-harness/SKILL.md +26 -3
- package/skills/tfx-harness/skill.json +5 -0
- package/skills/tfx-hooks/SKILL.md +0 -2
- package/skills/tfx-hooks/skill.json +0 -3
- package/skills/tfx-hub/SKILL.md +1 -6
- package/skills/tfx-hub/skill.json +0 -3
- package/skills/tfx-index/skill.json +0 -6
- package/skills/tfx-interview/SKILL.md +0 -2
- package/skills/tfx-live/SKILL.md +131 -5
- package/skills/tfx-live/skill.json +0 -5
- package/skills/tfx-plan/SKILL.md +7 -8
- package/skills/tfx-plan/skill.json +1 -12
- package/skills/tfx-profile/SKILL.md +15 -13
- package/skills/tfx-profile/skill.json +0 -3
- package/skills/tfx-prune/SKILL.md +4 -6
- package/skills/tfx-qa/SKILL.md +7 -7
- package/skills/tfx-qa/skill.json +1 -11
- package/skills/tfx-ralph/SKILL.md +8 -11
- package/skills/tfx-remote/SKILL.md +2 -2
- package/skills/tfx-remote/skill.json +0 -3
- package/skills/tfx-research/SKILL.md +2 -2
- package/skills/tfx-research/skill.json +1 -16
- package/skills/tfx-review/SKILL.md +11 -11
- package/skills/tfx-review/skill.json +1 -11
- package/skills/tfx-setup/SKILL.md +5 -6
- package/skills/tfx-setup/skill.json +0 -3
- package/skills/tfx-ship/SKILL.md +43 -36
- package/skills/tfx-ship/skill.json +1 -9
- package/skills/tfx-wt/skill.json +0 -7
- package/tui/codex-profile.mjs +3 -3
- package/tui/gemini-profile.mjs +11 -24
- package/tui/monitor.mjs +1 -0
- package/tui/setup.mjs +7 -6
- package/scripts/headless-guard-fast.sh +0 -29
- package/scripts/headless-guard.mjs +0 -523
- package/skills/tfx-autopilot/SKILL.md +0 -51
- package/skills/tfx-autopilot/skill.json +0 -12
- package/skills/tfx-codex-swarm-workspace/iteration-1/benchmark.json +0 -75
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/eval_metadata.json +0 -42
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/grading.json +0 -39
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/analysis.md +0 -87
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/classification.md +0 -35
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/commands.sh +0 -275
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/outputs/routing.md +0 -56
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/grading.json +0 -39
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/analysis.md +0 -92
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/classification.md +0 -71
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/commands.sh +0 -264
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/outputs/routing.md +0 -113
- package/skills/tfx-codex-swarm-workspace/iteration-1/full-swarm-all-prds/without_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/eval_metadata.json +0 -32
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/grading.json +0 -29
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/analysis.md +0 -96
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/classification.md +0 -38
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/commands.sh +0 -151
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/outputs/routing.md +0 -51
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/grading.json +0 -29
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/analysis.md +0 -127
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/classification.md +0 -57
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/commands.sh +0 -129
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/outputs/routing.md +0 -84
- package/skills/tfx-codex-swarm-workspace/iteration-1/implicit-swarm-no-keywords/without_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/eval_metadata.json +0 -27
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/grading.json +0 -24
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/analysis.md +0 -98
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/classification.md +0 -65
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/commands.sh +0 -123
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/outputs/routing.md +0 -66
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/with_skill/timing.json +0 -5
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/grading.json +0 -20
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/analysis.md +0 -88
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/classification.md +0 -40
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/commands.sh +0 -130
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/outputs/routing.md +0 -61
- package/skills/tfx-codex-swarm-workspace/iteration-1/selective-spawn-with-override/without_skill/timing.json +0 -5
- package/skills/tfx-consensus/SKILL.md +0 -56
- package/skills/tfx-consensus/skill.json +0 -8
- package/skills/tfx-debate/SKILL.md +0 -60
- package/skills/tfx-debate/skill.json +0 -14
- package/skills/tfx-fullcycle/SKILL.md +0 -47
- package/skills/tfx-fullcycle/skill.json +0 -13
- package/skills/tfx-multi/SKILL.md +0 -45
- package/skills/tfx-multi/references/agent-wrapper-rules.md +0 -94
- package/skills/tfx-multi/references/thorough-pipeline.md +0 -105
- package/skills/tfx-multi/skill.json +0 -10
- package/skills/tfx-panel/SKILL.md +0 -60
- package/skills/tfx-panel/skill.json +0 -14
- package/skills/tfx-persist/SKILL.md +0 -63
- package/skills/tfx-persist/skill.json +0 -14
- package/skills/tfx-psmux-rules/SKILL.md +0 -41
- package/skills/tfx-psmux-rules/skill.json +0 -10
- package/skills/tfx-remote-setup/SKILL.md +0 -42
- package/skills/tfx-remote-setup/skill.json +0 -10
- package/skills/tfx-remote-spawn/SKILL.md +0 -52
- package/skills/tfx-remote-spawn/skill.json +0 -10
- package/skills/tfx-swarm/SKILL.md +0 -49
- package/skills/tfx-swarm/skill.json +0 -13
package/hub/bridge.mjs
CHANGED
|
@@ -400,6 +400,16 @@ export function parseArgs(argv) {
|
|
|
400
400
|
command: { type: "string" },
|
|
401
401
|
role: { type: "string" },
|
|
402
402
|
"session-id": { type: "string" },
|
|
403
|
+
cwd: { type: "string" },
|
|
404
|
+
"worktree-path": { type: "string" },
|
|
405
|
+
branch: { type: "string" },
|
|
406
|
+
host: { type: "string" },
|
|
407
|
+
"session-kind": { type: "string" },
|
|
408
|
+
"is-remote": { type: "string" },
|
|
409
|
+
"tmux-session": { type: "string" },
|
|
410
|
+
"tmux-pane": { type: "string" },
|
|
411
|
+
"omx-session-id": { type: "string" },
|
|
412
|
+
"codex-session-id": { type: "string" },
|
|
403
413
|
reason: { type: "string" },
|
|
404
414
|
type: { type: "string" },
|
|
405
415
|
from: { type: "string" },
|
|
@@ -606,6 +616,71 @@ function unavailableResult() {
|
|
|
606
616
|
return { ok: false, reason: "hub_unavailable" };
|
|
607
617
|
}
|
|
608
618
|
|
|
619
|
+
function nonEmptyString(value, fallback = "") {
|
|
620
|
+
const normalized = String(value ?? "").trim();
|
|
621
|
+
return normalized || fallback;
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
function readBoolean(value) {
|
|
625
|
+
return ["1", "true", "yes"].includes(nonEmptyString(value).toLowerCase());
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function sessionAgentId(sessionId) {
|
|
629
|
+
return `codex-session-${sessionId.replace(/[^A-Za-z0-9._-]/g, "_")}`;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
export function buildInteractiveSessionRegistrationPayload(args = {}) {
|
|
633
|
+
const sessionId = nonEmptyString(args["session-id"]);
|
|
634
|
+
if (!sessionId) return null;
|
|
635
|
+
|
|
636
|
+
const cwd = nonEmptyString(args.cwd, process.cwd());
|
|
637
|
+
const worktreePath = nonEmptyString(args["worktree-path"], cwd);
|
|
638
|
+
const host = nonEmptyString(args.host, "local");
|
|
639
|
+
const sessionKind = nonEmptyString(args["session-kind"], "interactive");
|
|
640
|
+
const agentId = nonEmptyString(args.agent, sessionAgentId(sessionId));
|
|
641
|
+
const metadata = {
|
|
642
|
+
pid: process.ppid,
|
|
643
|
+
registered_at: Date.now(),
|
|
644
|
+
cwd,
|
|
645
|
+
worktree_path: worktreePath,
|
|
646
|
+
branch: nonEmptyString(args.branch),
|
|
647
|
+
host,
|
|
648
|
+
session_kind: sessionKind,
|
|
649
|
+
is_remote: readBoolean(args["is-remote"]),
|
|
650
|
+
...(nonEmptyString(args["tmux-session"])
|
|
651
|
+
? { tmux_session: nonEmptyString(args["tmux-session"]) }
|
|
652
|
+
: {}),
|
|
653
|
+
...(nonEmptyString(args["tmux-pane"])
|
|
654
|
+
? { tmux_pane: nonEmptyString(args["tmux-pane"]) }
|
|
655
|
+
: {}),
|
|
656
|
+
...(nonEmptyString(args["omx-session-id"])
|
|
657
|
+
? { omx_session_id: nonEmptyString(args["omx-session-id"]) }
|
|
658
|
+
: {}),
|
|
659
|
+
...(nonEmptyString(args["codex-session-id"])
|
|
660
|
+
? { codex_session_id: nonEmptyString(args["codex-session-id"]) }
|
|
661
|
+
: {}),
|
|
662
|
+
};
|
|
663
|
+
|
|
664
|
+
return {
|
|
665
|
+
sessionId,
|
|
666
|
+
cwd,
|
|
667
|
+
worktreePath,
|
|
668
|
+
branch: nonEmptyString(args.branch),
|
|
669
|
+
host,
|
|
670
|
+
sessionKind,
|
|
671
|
+
isRemote: readBoolean(args["is-remote"]),
|
|
672
|
+
agent_id: agentId,
|
|
673
|
+
cli: nonEmptyString(args.cli, "codex"),
|
|
674
|
+
capabilities: args.capabilities
|
|
675
|
+
? String(args.capabilities).split(",")
|
|
676
|
+
: ["code"],
|
|
677
|
+
topics: args.topics ? String(args.topics).split(",") : [],
|
|
678
|
+
heartbeat_ttl_ms: 300000,
|
|
679
|
+
session_id: sessionId,
|
|
680
|
+
metadata,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
609
684
|
function emitJson(payload) {
|
|
610
685
|
if (payload !== undefined) {
|
|
611
686
|
console.log(JSON.stringify(payload));
|
|
@@ -613,17 +688,33 @@ function emitJson(payload) {
|
|
|
613
688
|
return payload?.ok !== false;
|
|
614
689
|
}
|
|
615
690
|
|
|
691
|
+
const HUB_STORE_CLI_VALUES = new Set(["codex", "gemini", "claude", "other"]);
|
|
692
|
+
function normalizeCliForStore(cli) {
|
|
693
|
+
return HUB_STORE_CLI_VALUES.has(cli) ? cli : "other";
|
|
694
|
+
}
|
|
695
|
+
|
|
616
696
|
async function cmdRegister(args) {
|
|
697
|
+
const interactiveSession = buildInteractiveSessionRegistrationPayload(args);
|
|
698
|
+
if (interactiveSession) {
|
|
699
|
+
const result = await requestJson("/synapse/register", {
|
|
700
|
+
body: interactiveSession,
|
|
701
|
+
timeoutMs: 3000,
|
|
702
|
+
});
|
|
703
|
+
return emitJson(result || unavailableResult());
|
|
704
|
+
}
|
|
705
|
+
|
|
617
706
|
const agentId = args.agent;
|
|
618
707
|
const timeoutSec = parseInt(args.timeout || "600", 10);
|
|
708
|
+
const rawCli = args.cli || "other";
|
|
619
709
|
const outcome = await requestHub(HUB_OPERATIONS.register, {
|
|
620
710
|
agent_id: agentId,
|
|
621
|
-
cli:
|
|
711
|
+
cli: normalizeCliForStore(rawCli),
|
|
622
712
|
timeout_sec: timeoutSec,
|
|
623
713
|
heartbeat_ttl_ms: (timeoutSec + 120) * 1000,
|
|
624
714
|
topics: args.topics ? args.topics.split(",") : [],
|
|
625
715
|
capabilities: args.capabilities ? args.capabilities.split(",") : ["code"],
|
|
626
716
|
metadata: {
|
|
717
|
+
cli: rawCli,
|
|
627
718
|
pid: process.ppid,
|
|
628
719
|
registered_at: Date.now(),
|
|
629
720
|
},
|
|
@@ -634,8 +725,12 @@ async function cmdRegister(args) {
|
|
|
634
725
|
return emitJson({
|
|
635
726
|
ok: true,
|
|
636
727
|
agent_id: agentId,
|
|
728
|
+
lease_id: result.data?.lease_id,
|
|
729
|
+
presence_generation: result.data?.presence_generation,
|
|
637
730
|
lease_expires_ms: result.data?.lease_expires_ms,
|
|
638
731
|
pipe_path: result.data?.pipe_path || getHubPipePath(),
|
|
732
|
+
hub_instance_id: result.data?.hub_instance_id,
|
|
733
|
+
store_fingerprint: result.data?.store_fingerprint,
|
|
639
734
|
});
|
|
640
735
|
}
|
|
641
736
|
|
|
@@ -646,6 +741,10 @@ async function cmdHeartbeat(args) {
|
|
|
646
741
|
const outcome = await requestHub(HUB_OPERATIONS.heartbeat, {
|
|
647
742
|
agent_id: args.agent,
|
|
648
743
|
ttl_ms: args["ttl-ms"] != null ? Number(args["ttl-ms"]) : undefined,
|
|
744
|
+
presence_generation:
|
|
745
|
+
args.generation != null ? Number(args.generation) : undefined,
|
|
746
|
+
hub_instance_id: args["hub-instance-id"],
|
|
747
|
+
store_fingerprint: args["store-fingerprint"],
|
|
649
748
|
});
|
|
650
749
|
return emitJson(outcome?.result || unavailableResult());
|
|
651
750
|
}
|
|
@@ -731,6 +830,8 @@ async function cmdTakeoverRole(args) {
|
|
|
731
830
|
agent_id: agentId,
|
|
732
831
|
reason: args.reason || "manual",
|
|
733
832
|
requested_by: args["requested-by"] || "bridge",
|
|
833
|
+
hub_instance_id: args["hub-instance-id"],
|
|
834
|
+
store_fingerprint: args["store-fingerprint"],
|
|
734
835
|
});
|
|
735
836
|
const result = outcome?.result;
|
|
736
837
|
return emitJson(result || unavailableResult());
|
|
@@ -748,6 +849,8 @@ async function cmdSendInput(args) {
|
|
|
748
849
|
async function cmdContext(args) {
|
|
749
850
|
const outcome = await requestHub(HUB_OPERATIONS.context, {
|
|
750
851
|
agent_id: args.agent,
|
|
852
|
+
presence_generation:
|
|
853
|
+
args.generation != null ? Number(args.generation) : undefined,
|
|
751
854
|
topics: args.topics ? args.topics.split(",") : undefined,
|
|
752
855
|
max_messages: parseInt(args.max || "10", 10),
|
|
753
856
|
auto_ack: true,
|
|
@@ -793,13 +896,13 @@ async function cmdContext(args) {
|
|
|
793
896
|
async function cmdDeregister(args) {
|
|
794
897
|
const outcome = await requestHub(HUB_OPERATIONS.deregister, {
|
|
795
898
|
agent_id: args.agent,
|
|
899
|
+
presence_generation:
|
|
900
|
+
args.generation != null ? Number(args.generation) : undefined,
|
|
901
|
+
hub_instance_id: args["hub-instance-id"],
|
|
902
|
+
store_fingerprint: args["store-fingerprint"],
|
|
796
903
|
});
|
|
797
904
|
const result = outcome?.result;
|
|
798
905
|
|
|
799
|
-
if (result?.ok) {
|
|
800
|
-
return emitJson({ ok: true, agent_id: args.agent, status: "offline" });
|
|
801
|
-
}
|
|
802
|
-
|
|
803
906
|
return emitJson(result || unavailableResult());
|
|
804
907
|
}
|
|
805
908
|
|
|
@@ -1291,6 +1394,7 @@ async function cmdDaemonProbe(args) {
|
|
|
1291
1394
|
short: payload.short,
|
|
1292
1395
|
sessionId: payload.sessionId,
|
|
1293
1396
|
timeoutMs: numericOption(payload.timeoutMs, 6000),
|
|
1397
|
+
tmpRoot: payload.tmpRoot,
|
|
1294
1398
|
});
|
|
1295
1399
|
return emitJson(probe);
|
|
1296
1400
|
} catch (error) {
|
|
@@ -1314,6 +1418,7 @@ async function cmdDaemonAttach(args) {
|
|
|
1314
1418
|
short: payload.short,
|
|
1315
1419
|
sessionId: payload.sessionId,
|
|
1316
1420
|
timeoutMs: numericOption(payload.timeoutMs, 6000),
|
|
1421
|
+
tmpRoot: payload.tmpRoot,
|
|
1317
1422
|
});
|
|
1318
1423
|
if (!probe.ok) return emitJson(daemonAttachProbeFailureResult(probe));
|
|
1319
1424
|
const short = payload.short ?? probe.target?.short;
|
|
@@ -1382,6 +1487,7 @@ async function cmdDaemonInterrupt(args) {
|
|
|
1382
1487
|
short: payload.short,
|
|
1383
1488
|
sessionId: payload.sessionId,
|
|
1384
1489
|
timeoutMs: numericOption(payload.timeoutMs, 6000),
|
|
1490
|
+
tmpRoot: payload.tmpRoot,
|
|
1385
1491
|
});
|
|
1386
1492
|
if (!probe.ok) return emitJson(daemonInterruptProbeFailureResult(probe));
|
|
1387
1493
|
const short = payload.short ?? probe.target?.short;
|
package/hub/gemini-adapter.mjs
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
import { mkdirSync } from "node:fs";
|
|
5
5
|
import { tmpdir } from "node:os";
|
|
6
6
|
import { join } from "node:path";
|
|
7
|
+
import {
|
|
8
|
+
resolveGeminiModel,
|
|
9
|
+
resolveGeminiProfileForPurpose,
|
|
10
|
+
} from "../scripts/lib/gemini-profiles.mjs";
|
|
7
11
|
import {
|
|
8
12
|
executeWithCircuitBroker,
|
|
9
13
|
normalizePathForShell,
|
|
@@ -61,15 +65,13 @@ async function runPreflight(opts = {}) {
|
|
|
61
65
|
// ── Command building ────────────────────────────────────────────
|
|
62
66
|
|
|
63
67
|
function buildGeminiCommand(prompt, resultFile, opts = {}) {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
"--dangerously-skip-permissions",
|
|
72
|
-
];
|
|
68
|
+
// agy 의 --print 는 값(프롬프트)을 받는 플래그다. 1.1.27 부터 stdin 프롬프트는
|
|
69
|
+
// "empty prompt" 로 거부되므로 프롬프트를 --print 의 값으로, 맨 끝에 넘긴다.
|
|
70
|
+
const parts = ["agy", "--dangerously-skip-permissions"];
|
|
71
|
+
if (typeof opts.model === "string" && opts.model.trim()) {
|
|
72
|
+
parts.push("--model", shellSingleQuote(opts.model.trim()));
|
|
73
|
+
}
|
|
74
|
+
parts.push("--print", shellSingleQuote(prompt));
|
|
73
75
|
|
|
74
76
|
if (resultFile) {
|
|
75
77
|
return `${parts.join(" ")} > ${shellSingleQuote(normalizePathForShell(resultFile))} 2>${shellSingleQuote(normalizePathForShell(resultFile + ".err"))}`;
|
|
@@ -78,11 +80,27 @@ function buildGeminiCommand(prompt, resultFile, opts = {}) {
|
|
|
78
80
|
return parts.join(" ");
|
|
79
81
|
}
|
|
80
82
|
|
|
83
|
+
function resolveAntigravityModel(opts = {}) {
|
|
84
|
+
// effort 는 역할별 SSOT(scripts/lib/gemini-profiles.mjs). 명시 model 이 우선한다.
|
|
85
|
+
const explicit = typeof opts.model === "string" ? opts.model.trim() : "";
|
|
86
|
+
if (explicit)
|
|
87
|
+
return resolveGeminiModel(explicit, {
|
|
88
|
+
profilesPath: opts.geminiProfilesPath,
|
|
89
|
+
});
|
|
90
|
+
if (!opts.role && !opts.agent) return "";
|
|
91
|
+
return resolveGeminiModel(
|
|
92
|
+
resolveGeminiProfileForPurpose(opts.role || opts.agent),
|
|
93
|
+
{
|
|
94
|
+
profilesPath: opts.geminiProfilesPath,
|
|
95
|
+
},
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
|
|
81
99
|
function buildAttempts(opts, preflight) {
|
|
82
100
|
const timeout = Number.isFinite(opts.timeout) ? opts.timeout : 900_000;
|
|
83
101
|
const base = {
|
|
84
102
|
timeout,
|
|
85
|
-
model: opts
|
|
103
|
+
model: resolveAntigravityModel(opts),
|
|
86
104
|
allowedMcpServers: Array.isArray(opts.mcpServers)
|
|
87
105
|
? [...opts.mcpServers]
|
|
88
106
|
: [],
|
|
@@ -98,7 +116,7 @@ function buildAttempts(opts, preflight) {
|
|
|
98
116
|
export function buildExecArgs(opts = {}) {
|
|
99
117
|
const prompt = typeof opts.prompt === "string" ? opts.prompt : "";
|
|
100
118
|
return buildGeminiCommand(prompt, opts.resultFile || null, {
|
|
101
|
-
model: opts
|
|
119
|
+
model: resolveAntigravityModel(opts),
|
|
102
120
|
allowedMcpServers: opts.mcpServers,
|
|
103
121
|
});
|
|
104
122
|
}
|
package/hub/lib/memory-store.mjs
CHANGED
|
@@ -142,6 +142,7 @@ export function createMemoryStore() {
|
|
|
142
142
|
const store = {
|
|
143
143
|
type: "memory",
|
|
144
144
|
db: null,
|
|
145
|
+
fingerprint: "memory:ephemeral",
|
|
145
146
|
uuidv7,
|
|
146
147
|
|
|
147
148
|
close() {},
|
|
@@ -166,6 +167,7 @@ export function createMemoryStore() {
|
|
|
166
167
|
topics: clone(topics),
|
|
167
168
|
last_seen_ms: now,
|
|
168
169
|
lease_expires_ms: now + heartbeat_ttl_ms,
|
|
170
|
+
presence_generation: Number(current.presence_generation || 0) + 1,
|
|
169
171
|
status: "online",
|
|
170
172
|
metadata: clone(metadata),
|
|
171
173
|
};
|
|
@@ -173,6 +175,7 @@ export function createMemoryStore() {
|
|
|
173
175
|
return {
|
|
174
176
|
agent_id,
|
|
175
177
|
lease_id: uuidv7(),
|
|
178
|
+
presence_generation: next.presence_generation,
|
|
176
179
|
lease_expires_ms: next.lease_expires_ms,
|
|
177
180
|
server_time_ms: now,
|
|
178
181
|
effective: {
|
|
@@ -183,6 +186,7 @@ export function createMemoryStore() {
|
|
|
183
186
|
lease_expires_ms: next.lease_expires_ms,
|
|
184
187
|
store_type: "memory",
|
|
185
188
|
db_path: null,
|
|
189
|
+
store_fingerprint: "memory:ephemeral",
|
|
186
190
|
},
|
|
187
191
|
};
|
|
188
192
|
},
|
|
@@ -191,14 +195,23 @@ export function createMemoryStore() {
|
|
|
191
195
|
return clone(agents.get(id) || null);
|
|
192
196
|
},
|
|
193
197
|
|
|
194
|
-
refreshLease(agentId, ttlMs = 30000) {
|
|
198
|
+
refreshLease(agentId, ttlMs = 30000, presenceGeneration) {
|
|
195
199
|
const current = agents.get(agentId);
|
|
196
|
-
if (
|
|
200
|
+
if (
|
|
201
|
+
!current ||
|
|
202
|
+
(presenceGeneration != null &&
|
|
203
|
+
current.presence_generation !== presenceGeneration)
|
|
204
|
+
)
|
|
197
205
|
return {
|
|
198
206
|
agent_id: agentId,
|
|
199
207
|
lease_expires_ms: Date.now() + ttlMs,
|
|
200
208
|
server_time_ms: Date.now(),
|
|
201
|
-
effective: {
|
|
209
|
+
effective: {
|
|
210
|
+
updated: false,
|
|
211
|
+
store_type: "memory",
|
|
212
|
+
db_path: null,
|
|
213
|
+
store_fingerprint: "memory:ephemeral",
|
|
214
|
+
},
|
|
202
215
|
};
|
|
203
216
|
const now = Date.now();
|
|
204
217
|
current.last_seen_ms = now;
|
|
@@ -208,7 +221,12 @@ export function createMemoryStore() {
|
|
|
208
221
|
agent_id: agentId,
|
|
209
222
|
lease_expires_ms: current.lease_expires_ms,
|
|
210
223
|
server_time_ms: now,
|
|
211
|
-
effective: {
|
|
224
|
+
effective: {
|
|
225
|
+
updated: true,
|
|
226
|
+
store_type: "memory",
|
|
227
|
+
db_path: null,
|
|
228
|
+
store_fingerprint: "memory:ephemeral",
|
|
229
|
+
},
|
|
212
230
|
};
|
|
213
231
|
},
|
|
214
232
|
|
|
@@ -243,9 +261,19 @@ export function createMemoryStore() {
|
|
|
243
261
|
|
|
244
262
|
sweepStaleAgents() {
|
|
245
263
|
const now = Date.now();
|
|
264
|
+
const candidates = Array.from(agents.values(), (agent) => ({
|
|
265
|
+
agent_id: agent.agent_id,
|
|
266
|
+
presence_generation: agent.presence_generation,
|
|
267
|
+
}));
|
|
246
268
|
let stale = 0;
|
|
247
269
|
let offline = 0;
|
|
248
|
-
for (const
|
|
270
|
+
for (const candidate of candidates) {
|
|
271
|
+
const agent = agents.get(candidate.agent_id);
|
|
272
|
+
if (
|
|
273
|
+
!agent ||
|
|
274
|
+
agent.presence_generation !== candidate.presence_generation
|
|
275
|
+
)
|
|
276
|
+
continue;
|
|
249
277
|
if (agent.status === "online" && agent.lease_expires_ms < now) {
|
|
250
278
|
agent.status = "stale";
|
|
251
279
|
stale += 1;
|
|
@@ -260,9 +288,14 @@ export function createMemoryStore() {
|
|
|
260
288
|
return { stale, offline };
|
|
261
289
|
},
|
|
262
290
|
|
|
263
|
-
updateAgentStatus(agentId, status) {
|
|
291
|
+
updateAgentStatus(agentId, status, presenceGeneration) {
|
|
264
292
|
const current = agents.get(agentId);
|
|
265
|
-
if (
|
|
293
|
+
if (
|
|
294
|
+
!current ||
|
|
295
|
+
(presenceGeneration != null &&
|
|
296
|
+
current.presence_generation !== presenceGeneration)
|
|
297
|
+
)
|
|
298
|
+
return false;
|
|
266
299
|
current.status = status;
|
|
267
300
|
return true;
|
|
268
301
|
},
|
|
@@ -421,21 +454,11 @@ export function createMemoryStore() {
|
|
|
421
454
|
.map((request) => clone(request));
|
|
422
455
|
},
|
|
423
456
|
|
|
424
|
-
expireHumanRequests() {
|
|
425
|
-
let changed = 0;
|
|
426
|
-
const now = Date.now();
|
|
427
|
-
for (const request of humanRequests.values()) {
|
|
428
|
-
if (request.state === "pending" && request.deadline_ms < now) {
|
|
429
|
-
request.state = "timed_out";
|
|
430
|
-
changed += 1;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return changed;
|
|
434
|
-
},
|
|
435
|
-
|
|
436
457
|
moveToDeadLetter(messageId, reason, lastError = null) {
|
|
437
458
|
const current = messages.get(messageId);
|
|
438
|
-
if (current
|
|
459
|
+
if (!current || current.status === "dead_letter") return false;
|
|
460
|
+
current.status = "dead_letter";
|
|
461
|
+
if (deadLetters.has(messageId)) return true;
|
|
439
462
|
deadLetters.set(messageId, {
|
|
440
463
|
message_id: messageId,
|
|
441
464
|
reason,
|
|
@@ -685,25 +708,38 @@ export function createMemoryStore() {
|
|
|
685
708
|
});
|
|
686
709
|
},
|
|
687
710
|
|
|
688
|
-
sweepExpired() {
|
|
689
|
-
const
|
|
690
|
-
let expiredMessages = 0;
|
|
711
|
+
sweepExpired({ now_ms = Date.now() } = {}) {
|
|
712
|
+
const transitions = [];
|
|
691
713
|
for (const message of messages.values()) {
|
|
692
|
-
if (
|
|
693
|
-
message.status
|
|
714
|
+
if (
|
|
715
|
+
!["queued", "delivered"].includes(message.status) ||
|
|
716
|
+
message.expires_at_ms > now_ms
|
|
717
|
+
)
|
|
718
|
+
continue;
|
|
719
|
+
const snapshot = clone(message);
|
|
720
|
+
const previousStatus = message.status;
|
|
721
|
+
message.status = "dead_letter";
|
|
722
|
+
const dlqInserted = !deadLetters.has(message.id);
|
|
723
|
+
if (dlqInserted) {
|
|
694
724
|
deadLetters.set(message.id, {
|
|
695
725
|
message_id: message.id,
|
|
696
726
|
reason: "ttl_expired",
|
|
697
|
-
failed_at_ms:
|
|
727
|
+
failed_at_ms: now_ms,
|
|
698
728
|
last_error: null,
|
|
699
729
|
});
|
|
700
|
-
expiredMessages += 1;
|
|
701
730
|
}
|
|
731
|
+
transitions.push({
|
|
732
|
+
message: snapshot,
|
|
733
|
+
previous_status: previousStatus,
|
|
734
|
+
reason: "ttl_expired",
|
|
735
|
+
failed_at_ms: now_ms,
|
|
736
|
+
dlq_inserted: dlqInserted,
|
|
737
|
+
});
|
|
702
738
|
}
|
|
703
|
-
const humanRequestsExpired = store.expireHumanRequests();
|
|
704
739
|
return {
|
|
705
|
-
|
|
706
|
-
|
|
740
|
+
now_ms,
|
|
741
|
+
messages: transitions.length,
|
|
742
|
+
transitions,
|
|
707
743
|
};
|
|
708
744
|
},
|
|
709
745
|
|
|
@@ -8,11 +8,12 @@
|
|
|
8
8
|
//
|
|
9
9
|
// 기존 플래그 (Phase 2 v10.9.33+):
|
|
10
10
|
// --cli {auto|codex|antigravity|claude}
|
|
11
|
-
// --mode {quick|deep|consensus}
|
|
11
|
+
// --mode {quick|deep|consensus|live}
|
|
12
12
|
// --parallel {1|N|swarm}
|
|
13
13
|
// --retry {0|1|ralph|auto-escalate} (Phase 3 에서 ralph/auto-escalate 신규)
|
|
14
14
|
// --isolation {none|worktree}
|
|
15
15
|
// --remote {none|<host>}
|
|
16
|
+
// --rounds <N> (--mode live 전용, 기본 4)
|
|
16
17
|
//
|
|
17
18
|
// Phase 3 신규:
|
|
18
19
|
// --lead {claude|codex} (tfx-auto-codex 의미 흡수)
|
|
@@ -31,11 +32,12 @@ export const DEFAULT_OPTIONS = Object.freeze({
|
|
|
31
32
|
lead: "claude",
|
|
32
33
|
noClaudeNative: false,
|
|
33
34
|
maxIterations: 0,
|
|
35
|
+
rounds: 4,
|
|
34
36
|
});
|
|
35
37
|
|
|
36
38
|
const VALID_VALUES = Object.freeze({
|
|
37
39
|
cli: ["auto", "codex", "antigravity", "claude"],
|
|
38
|
-
mode: ["quick", "deep", "consensus"],
|
|
40
|
+
mode: ["quick", "deep", "consensus", "live"],
|
|
39
41
|
retry: ["0", "1", "ralph", "auto-escalate"],
|
|
40
42
|
isolation: ["none", "worktree"],
|
|
41
43
|
lead: ["claude", "codex"],
|
|
@@ -50,6 +52,7 @@ const VALUE_FLAGS = new Set([
|
|
|
50
52
|
"--remote",
|
|
51
53
|
"--lead",
|
|
52
54
|
"--max-iterations",
|
|
55
|
+
"--rounds",
|
|
53
56
|
]);
|
|
54
57
|
|
|
55
58
|
const BOOL_FLAGS = new Set(["--no-claude-native"]);
|
|
@@ -61,12 +64,14 @@ export function parseArgs(input) {
|
|
|
61
64
|
const opts = { ...DEFAULT_OPTIONS };
|
|
62
65
|
const warnings = [];
|
|
63
66
|
const taskTokens = [];
|
|
67
|
+
const providedFlags = new Set();
|
|
64
68
|
|
|
65
69
|
let i = 0;
|
|
66
70
|
while (i < tokens.length) {
|
|
67
71
|
const raw = tokens[i];
|
|
68
72
|
|
|
69
73
|
if (BOOL_FLAGS.has(raw)) {
|
|
74
|
+
providedFlags.add(raw);
|
|
70
75
|
applyBool(opts, raw);
|
|
71
76
|
i += 1;
|
|
72
77
|
continue;
|
|
@@ -82,6 +87,7 @@ export function parseArgs(input) {
|
|
|
82
87
|
}
|
|
83
88
|
|
|
84
89
|
if (VALUE_FLAGS.has(flag)) {
|
|
90
|
+
providedFlags.add(flag);
|
|
85
91
|
if (value === null) {
|
|
86
92
|
const next = tokens[i + 1];
|
|
87
93
|
if (next === undefined || next.startsWith("--")) {
|
|
@@ -108,7 +114,7 @@ export function parseArgs(input) {
|
|
|
108
114
|
i += 1;
|
|
109
115
|
}
|
|
110
116
|
|
|
111
|
-
validate(opts, warnings);
|
|
117
|
+
validate(opts, warnings, providedFlags);
|
|
112
118
|
|
|
113
119
|
return {
|
|
114
120
|
...opts,
|
|
@@ -196,10 +202,19 @@ function applyValue(opts, flag, value, warnings) {
|
|
|
196
202
|
}
|
|
197
203
|
break;
|
|
198
204
|
}
|
|
205
|
+
case "--rounds": {
|
|
206
|
+
const n = Number(value);
|
|
207
|
+
if (!Number.isInteger(n) || n <= 0) {
|
|
208
|
+
warnings.push(`invalid --rounds=${value}, expected positive integer`);
|
|
209
|
+
} else {
|
|
210
|
+
opts.rounds = n;
|
|
211
|
+
}
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
199
214
|
}
|
|
200
215
|
}
|
|
201
216
|
|
|
202
|
-
function validate(opts, warnings) {
|
|
217
|
+
function validate(opts, warnings, providedFlags = new Set()) {
|
|
203
218
|
for (const key of Object.keys(VALID_VALUES)) {
|
|
204
219
|
if (!VALID_VALUES[key].includes(opts[key])) {
|
|
205
220
|
warnings.push(
|
|
@@ -214,6 +229,28 @@ function validate(opts, warnings) {
|
|
|
214
229
|
) {
|
|
215
230
|
warnings.push(`invalid --parallel=${opts.parallel}, expected 1|N|swarm`);
|
|
216
231
|
}
|
|
232
|
+
|
|
233
|
+
if (opts.mode === "live") {
|
|
234
|
+
const ignored = [
|
|
235
|
+
["--parallel", "parallel", DEFAULT_OPTIONS.parallel],
|
|
236
|
+
["--isolation", "isolation", DEFAULT_OPTIONS.isolation],
|
|
237
|
+
["--remote", "remote", DEFAULT_OPTIONS.remote],
|
|
238
|
+
];
|
|
239
|
+
for (const [flag, key, fallback] of ignored) {
|
|
240
|
+
if (providedFlags.has(flag)) {
|
|
241
|
+
warnings.push(`${flag} ignored with --mode live`);
|
|
242
|
+
opts[key] = fallback;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (providedFlags.has("--retry") && opts.retry === "ralph") {
|
|
246
|
+
warnings.push("--retry ralph ignored with --mode live");
|
|
247
|
+
opts.retry = DEFAULT_OPTIONS.retry;
|
|
248
|
+
}
|
|
249
|
+
} else if (providedFlags.has("--rounds")) {
|
|
250
|
+
warnings.push("--rounds ignored unless --mode live");
|
|
251
|
+
opts.rounds = DEFAULT_OPTIONS.rounds;
|
|
252
|
+
}
|
|
253
|
+
|
|
217
254
|
const parallelOne = opts.parallel === "1" || opts.parallel === 1;
|
|
218
255
|
if (parallelOne && opts.isolation === "worktree") {
|
|
219
256
|
warnings.push(
|
package/hub/pipe.mjs
CHANGED
|
@@ -267,18 +267,11 @@ export function createPipeServer({
|
|
|
267
267
|
const result = router.refreshAgentLease(
|
|
268
268
|
agentId,
|
|
269
269
|
payload.heartbeat_ttl_ms || heartbeatTtlMs,
|
|
270
|
+
payload.presence_generation,
|
|
271
|
+
payload,
|
|
270
272
|
);
|
|
271
273
|
if (client) touchClient(client);
|
|
272
|
-
|
|
273
|
-
return {
|
|
274
|
-
ok: false,
|
|
275
|
-
error: {
|
|
276
|
-
code: "AGENT_NOT_FOUND",
|
|
277
|
-
message: `heartbeat target not registered: ${agentId}`,
|
|
278
|
-
},
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
return { ok: true, data: result };
|
|
274
|
+
return result;
|
|
282
275
|
}
|
|
283
276
|
|
|
284
277
|
case "publish": {
|
|
@@ -357,12 +350,14 @@ export function createPipeServer({
|
|
|
357
350
|
|
|
358
351
|
case "deregister": {
|
|
359
352
|
const agentId = resolveAgentId(client, payload);
|
|
360
|
-
router.
|
|
353
|
+
const result = router.transitionAgentStatus(
|
|
354
|
+
agentId,
|
|
355
|
+
"offline",
|
|
356
|
+
payload.presence_generation,
|
|
357
|
+
payload,
|
|
358
|
+
);
|
|
361
359
|
if (client) touchClient(client);
|
|
362
|
-
return
|
|
363
|
-
ok: true,
|
|
364
|
-
data: { agent_id: agentId, status: "offline" },
|
|
365
|
-
};
|
|
360
|
+
return result;
|
|
366
361
|
}
|
|
367
362
|
|
|
368
363
|
case "send_input": {
|
package/hub/reflexion.mjs
CHANGED
|
@@ -7,8 +7,6 @@ const DEFAULT_CONFIDENCE = 0.5;
|
|
|
7
7
|
const ACTIVE_RULE_CONFIDENCE = 0.5;
|
|
8
8
|
const ADAPTIVE_PROMOTION_STEP = 0.1;
|
|
9
9
|
const ADAPTIVE_DECAY_STEP = 0.1;
|
|
10
|
-
/** @deprecated 세션 기반 decay에서 시간 기반으로 변경됨. 미사용. */
|
|
11
|
-
const _ADAPTIVE_DECAY_WINDOW = 5;
|
|
12
10
|
const ADAPTIVE_DELETE_THRESHOLD = 0.3;
|
|
13
11
|
|
|
14
12
|
function clampConfidence(value) {
|
|
@@ -102,61 +100,6 @@ function buildAdaptiveSolution(errorContext = {}, errorText = "") {
|
|
|
102
100
|
return `${toolName} 재시도 전 실패 원인을 검증하세요: ${summary}`;
|
|
103
101
|
}
|
|
104
102
|
|
|
105
|
-
function normalizeSessionIds(sessionIds) {
|
|
106
|
-
if (!Array.isArray(sessionIds)) return [];
|
|
107
|
-
return [
|
|
108
|
-
...new Set(
|
|
109
|
-
sessionIds.filter((value) => typeof value === "string" && value.trim()),
|
|
110
|
-
),
|
|
111
|
-
];
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** @deprecated reflexion_entries 기반. adaptive_rules에서는 미사용. 세션 인식 복원 시 재활용 예정. */
|
|
115
|
-
function getAdaptiveState(rule = {}) {
|
|
116
|
-
const state = rule.adaptive_state || {};
|
|
117
|
-
const session_ids = normalizeSessionIds(state.session_ids);
|
|
118
|
-
return {
|
|
119
|
-
...state,
|
|
120
|
-
project_slug: pickString(state.project_slug, rule.context?.project_slug),
|
|
121
|
-
session_ids,
|
|
122
|
-
session_occurrences: Math.max(
|
|
123
|
-
state.session_occurrences || 0,
|
|
124
|
-
session_ids.length,
|
|
125
|
-
),
|
|
126
|
-
last_seen_session: pickSessionCount(state.last_seen_session),
|
|
127
|
-
last_decay_session: pickSessionCount(state.last_decay_session),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** @deprecated reflexion_entries 기반. adaptive_rules에서는 미사용. 세션 인식 복원 시 재활용 예정. */
|
|
132
|
-
function _mergeAdaptiveState(rule, errorContext = {}) {
|
|
133
|
-
const current = getAdaptiveState(rule);
|
|
134
|
-
const sessionId = pickSessionId(errorContext);
|
|
135
|
-
const sessionCount = pickSessionCount(
|
|
136
|
-
errorContext.sessionCount,
|
|
137
|
-
errorContext.session_count,
|
|
138
|
-
errorContext.context?.sessionCount,
|
|
139
|
-
errorContext.context?.session_count,
|
|
140
|
-
);
|
|
141
|
-
const session_ids = normalizeSessionIds(
|
|
142
|
-
sessionId ? [...current.session_ids, sessionId] : current.session_ids,
|
|
143
|
-
);
|
|
144
|
-
return {
|
|
145
|
-
...current,
|
|
146
|
-
project_slug: pickString(
|
|
147
|
-
pickProjectSlug(errorContext),
|
|
148
|
-
current.project_slug,
|
|
149
|
-
),
|
|
150
|
-
session_ids,
|
|
151
|
-
session_occurrences: Math.max(
|
|
152
|
-
current.session_occurrences,
|
|
153
|
-
session_ids.length,
|
|
154
|
-
),
|
|
155
|
-
last_seen_session: Math.max(current.last_seen_session, sessionCount),
|
|
156
|
-
last_decay_session: current.last_decay_session || sessionCount,
|
|
157
|
-
};
|
|
158
|
-
}
|
|
159
|
-
|
|
160
103
|
function filterEntriesByType(entries, type) {
|
|
161
104
|
return entries.filter(
|
|
162
105
|
(entry) => (entry.type || DEFAULT_REFLEXION_TYPE) === type,
|