@vtxmacro/cli 2026.8.52 → 2026.8.54
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 +83 -31
- package/bin/vtx.js +2427 -190
- package/package.json +52 -4
package/bin/vtx.js
CHANGED
|
@@ -47,13 +47,67 @@ var init_agent_cli_release = __esm({
|
|
|
47
47
|
"agent-cli-release.json"() {
|
|
48
48
|
agent_cli_release_default = {
|
|
49
49
|
package_name: "@vtxmacro/cli",
|
|
50
|
-
package_version: "2026.8.
|
|
50
|
+
package_version: "2026.8.54",
|
|
51
51
|
codex_package_name: "@openai/codex",
|
|
52
52
|
codex_version: "0.147.0",
|
|
53
53
|
copilot_sdk_package_name: "@github/copilot-sdk",
|
|
54
54
|
copilot_sdk_version: "1.0.0-beta.8",
|
|
55
55
|
copilot_cli_package_name: "@github/copilot",
|
|
56
56
|
copilot_cli_version: "1.0.80",
|
|
57
|
+
deepseek_harness_version: "0.1.1-rc.2",
|
|
58
|
+
deepseek_harness_packages: [
|
|
59
|
+
"@deepseek-ai/dsh-agent",
|
|
60
|
+
"@deepseek-ai/dsh-agent-instructions",
|
|
61
|
+
"@deepseek-ai/dsh-agent-loop",
|
|
62
|
+
"@deepseek-ai/dsh-agent-spine-demo",
|
|
63
|
+
"@deepseek-ai/dsh-anonymous-user-id",
|
|
64
|
+
"@deepseek-ai/dsh-atomic-write",
|
|
65
|
+
"@deepseek-ai/dsh-attachment",
|
|
66
|
+
"@deepseek-ai/dsh-brand",
|
|
67
|
+
"@deepseek-ai/dsh-code-runtime",
|
|
68
|
+
"@deepseek-ai/dsh-credentials",
|
|
69
|
+
"@deepseek-ai/dsh-fs",
|
|
70
|
+
"@deepseek-ai/dsh-goal",
|
|
71
|
+
"@deepseek-ai/dsh-goal-round-driver",
|
|
72
|
+
"@deepseek-ai/dsh-home-paths",
|
|
73
|
+
"@deepseek-ai/dsh-invariants",
|
|
74
|
+
"@deepseek-ai/dsh-jobs",
|
|
75
|
+
"@deepseek-ai/dsh-jobs-local",
|
|
76
|
+
"@deepseek-ai/dsh-launch-environment",
|
|
77
|
+
"@deepseek-ai/dsh-llm",
|
|
78
|
+
"@deepseek-ai/dsh-llm-deepseek",
|
|
79
|
+
"@deepseek-ai/dsh-llm-retry",
|
|
80
|
+
"@deepseek-ai/dsh-output-retention",
|
|
81
|
+
"@deepseek-ai/dsh-sandbox",
|
|
82
|
+
"@deepseek-ai/dsh-sandbox-policy",
|
|
83
|
+
"@deepseek-ai/dsh-scope",
|
|
84
|
+
"@deepseek-ai/dsh-session",
|
|
85
|
+
"@deepseek-ai/dsh-session-checkpoint-policy",
|
|
86
|
+
"@deepseek-ai/dsh-session-persistence",
|
|
87
|
+
"@deepseek-ai/dsh-session-persistence-jsonl",
|
|
88
|
+
"@deepseek-ai/dsh-session-projection",
|
|
89
|
+
"@deepseek-ai/dsh-session-title",
|
|
90
|
+
"@deepseek-ai/dsh-settings",
|
|
91
|
+
"@deepseek-ai/dsh-shell",
|
|
92
|
+
"@deepseek-ai/dsh-shell-env",
|
|
93
|
+
"@deepseek-ai/dsh-skill",
|
|
94
|
+
"@deepseek-ai/dsh-skill-filesystem",
|
|
95
|
+
"@deepseek-ai/dsh-subprocess",
|
|
96
|
+
"@deepseek-ai/dsh-system-prompt",
|
|
97
|
+
"@deepseek-ai/dsh-timeout",
|
|
98
|
+
"@deepseek-ai/dsh-tool-bash",
|
|
99
|
+
"@deepseek-ai/dsh-tool-goal",
|
|
100
|
+
"@deepseek-ai/dsh-tool-jobs",
|
|
101
|
+
"@deepseek-ai/dsh-tool-skill",
|
|
102
|
+
"@deepseek-ai/dsh-tools",
|
|
103
|
+
"@deepseek-ai/dsh-typert-protocol",
|
|
104
|
+
"@deepseek-ai/dsh-user-approval"
|
|
105
|
+
],
|
|
106
|
+
deepseek_cordis_package_name: "@deepseek-ai/cordis",
|
|
107
|
+
deepseek_cordis_version: "4.0.1",
|
|
108
|
+
deepseek_support_packages: {
|
|
109
|
+
"@deepseek-ai/cordis-plugin-timer": "1.1.3"
|
|
110
|
+
},
|
|
57
111
|
platforms: {
|
|
58
112
|
"linux-x64": {
|
|
59
113
|
package_name: "@openai/codex-linux-x64",
|
|
@@ -19695,32 +19749,88 @@ var init_agent_client = __esm({
|
|
|
19695
19749
|
});
|
|
19696
19750
|
|
|
19697
19751
|
// lib/inference-host/agent-state.ts
|
|
19698
|
-
async function
|
|
19752
|
+
async function readInferenceAgentFailureFence(statePath) {
|
|
19753
|
+
const raw = await readInferencePrivateFile(
|
|
19754
|
+
inferenceAgentFailureFencePath(statePath),
|
|
19755
|
+
"Inference Agent failure fence"
|
|
19756
|
+
);
|
|
19757
|
+
if (raw === null) return null;
|
|
19758
|
+
try {
|
|
19759
|
+
return assertInferenceAgentFailureFence(JSON.parse(raw));
|
|
19760
|
+
} catch (error48) {
|
|
19761
|
+
if (error48 instanceof SyntaxError) {
|
|
19762
|
+
throw new Error("Inference Agent failure fence is not valid JSON.");
|
|
19763
|
+
}
|
|
19764
|
+
throw error48;
|
|
19765
|
+
}
|
|
19766
|
+
}
|
|
19767
|
+
async function writeInferenceAgentFailureFence(statePath, value) {
|
|
19768
|
+
await writeAtomicInferencePrivateFile(
|
|
19769
|
+
inferenceAgentFailureFencePath(statePath),
|
|
19770
|
+
`${JSON.stringify(assertInferenceAgentFailureFence(value), null, 2)}
|
|
19771
|
+
`
|
|
19772
|
+
);
|
|
19773
|
+
}
|
|
19774
|
+
async function clearInferenceAgentFailureFence(statePath) {
|
|
19775
|
+
await clearInferencePrivateFile(
|
|
19776
|
+
inferenceAgentFailureFencePath(statePath),
|
|
19777
|
+
"Inference Agent failure fence"
|
|
19778
|
+
);
|
|
19779
|
+
}
|
|
19780
|
+
async function readInferenceAgentRuntimeState(statePath) {
|
|
19781
|
+
const raw = await readInferencePrivateFile(
|
|
19782
|
+
inferenceAgentRuntimeStatePath(statePath),
|
|
19783
|
+
"Inference Agent runtime recovery state"
|
|
19784
|
+
);
|
|
19785
|
+
if (raw === null) return null;
|
|
19786
|
+
try {
|
|
19787
|
+
return assertInferenceAgentRuntimeState(JSON.parse(raw));
|
|
19788
|
+
} catch (error48) {
|
|
19789
|
+
if (error48 instanceof SyntaxError) {
|
|
19790
|
+
throw new Error("Inference Agent runtime recovery state is not valid JSON.");
|
|
19791
|
+
}
|
|
19792
|
+
throw error48;
|
|
19793
|
+
}
|
|
19794
|
+
}
|
|
19795
|
+
async function writeInferenceAgentRuntimeState(statePath, value) {
|
|
19796
|
+
await writeAtomicInferencePrivateFile(
|
|
19797
|
+
inferenceAgentRuntimeStatePath(statePath),
|
|
19798
|
+
`${JSON.stringify(assertInferenceAgentRuntimeState(value), null, 2)}
|
|
19799
|
+
`
|
|
19800
|
+
);
|
|
19801
|
+
}
|
|
19802
|
+
async function clearInferenceAgentRuntimeState(statePath) {
|
|
19803
|
+
await clearInferencePrivateFile(
|
|
19804
|
+
inferenceAgentRuntimeStatePath(statePath),
|
|
19805
|
+
"Inference Agent runtime recovery state"
|
|
19806
|
+
);
|
|
19807
|
+
}
|
|
19808
|
+
async function readInferenceForegroundAgentControlState(statePath) {
|
|
19699
19809
|
const raw = await readInferencePrivateFile(
|
|
19700
|
-
|
|
19701
|
-
"
|
|
19810
|
+
foregroundAgentControlStatePath(statePath),
|
|
19811
|
+
"Foreground Agent control recovery state"
|
|
19702
19812
|
);
|
|
19703
19813
|
if (raw === null) return null;
|
|
19704
19814
|
try {
|
|
19705
|
-
return
|
|
19815
|
+
return assertForegroundAgentControlState(JSON.parse(raw));
|
|
19706
19816
|
} catch (error48) {
|
|
19707
19817
|
if (error48 instanceof SyntaxError) {
|
|
19708
|
-
throw new Error("
|
|
19818
|
+
throw new Error("Foreground Agent control recovery state is not valid JSON.");
|
|
19709
19819
|
}
|
|
19710
19820
|
throw error48;
|
|
19711
19821
|
}
|
|
19712
19822
|
}
|
|
19713
|
-
async function
|
|
19823
|
+
async function writeInferenceForegroundAgentControlState(statePath, value) {
|
|
19714
19824
|
await writeAtomicInferencePrivateFile(
|
|
19715
|
-
|
|
19716
|
-
`${JSON.stringify(
|
|
19825
|
+
foregroundAgentControlStatePath(statePath),
|
|
19826
|
+
`${JSON.stringify(assertForegroundAgentControlState(value), null, 2)}
|
|
19717
19827
|
`
|
|
19718
19828
|
);
|
|
19719
19829
|
}
|
|
19720
|
-
async function
|
|
19830
|
+
async function clearInferenceForegroundAgentControlState(statePath) {
|
|
19721
19831
|
await clearInferencePrivateFile(
|
|
19722
|
-
|
|
19723
|
-
"
|
|
19832
|
+
foregroundAgentControlStatePath(statePath),
|
|
19833
|
+
"Foreground Agent control recovery state"
|
|
19724
19834
|
);
|
|
19725
19835
|
}
|
|
19726
19836
|
async function readInferenceAgentAttemptState(statePath) {
|
|
@@ -19779,7 +19889,7 @@ async function clearInferenceAgentNextState(statePath) {
|
|
|
19779
19889
|
"Agent-driven inference next recovery state"
|
|
19780
19890
|
);
|
|
19781
19891
|
}
|
|
19782
|
-
var inferenceAgentAttemptStatePath, inferenceAgentNextStatePath,
|
|
19892
|
+
var inferenceAgentAttemptStatePath, inferenceAgentNextStatePath, inferenceAgentRuntimeStatePath, inferenceAgentFailureFencePath, isIsoTimestamp, assertPlainObject, hasExactKeys, assertInferenceAgentFailureFence, assertInferenceAgentRuntimeState, readCodexAgentRuntimeState, clearCodexAgentRuntimeState, foregroundAgentControlStatePath, assertRuntimeAssignment, assertForegroundAgentControlState, assertNextState, assertAttemptState;
|
|
19783
19893
|
var init_agent_state = __esm({
|
|
19784
19894
|
"lib/inference-host/agent-state.ts"() {
|
|
19785
19895
|
"use strict";
|
|
@@ -19787,18 +19897,39 @@ var init_agent_state = __esm({
|
|
|
19787
19897
|
init_external_inference_contract();
|
|
19788
19898
|
inferenceAgentAttemptStatePath = (statePath) => `${statePath}.agent-attempt.json`;
|
|
19789
19899
|
inferenceAgentNextStatePath = (statePath) => `${statePath}.agent-next.json`;
|
|
19790
|
-
|
|
19900
|
+
inferenceAgentRuntimeStatePath = (statePath) => `${statePath}.codex-agent-runtime.json`;
|
|
19901
|
+
inferenceAgentFailureFencePath = (statePath) => `${statePath}.agent-failure-fence.json`;
|
|
19791
19902
|
isIsoTimestamp = (value) => typeof value === "string" && Number.isFinite(Date.parse(value));
|
|
19792
19903
|
assertPlainObject = (value, message) => {
|
|
19793
19904
|
if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error(message);
|
|
19794
19905
|
return value;
|
|
19795
19906
|
};
|
|
19796
19907
|
hasExactKeys = (record2, keys) => Object.keys(record2).sort().join("\0") === [...keys].sort().join("\0");
|
|
19797
|
-
|
|
19798
|
-
const message = "
|
|
19908
|
+
assertInferenceAgentFailureFence = (value) => {
|
|
19909
|
+
const message = "Inference Agent failure fence is invalid.";
|
|
19910
|
+
const fence = assertPlainObject(value, message);
|
|
19911
|
+
if (!hasExactKeys(fence, [
|
|
19912
|
+
"schema_version",
|
|
19913
|
+
"adapter_id",
|
|
19914
|
+
"host_id",
|
|
19915
|
+
"assignment_id",
|
|
19916
|
+
"failure_category",
|
|
19917
|
+
"failure_code",
|
|
19918
|
+
"dispatch_outcome",
|
|
19919
|
+
"retry_at",
|
|
19920
|
+
"created_at"
|
|
19921
|
+
]) || fence.schema_version !== "vtx_inference_agent_failure_fence_v1" || typeof fence.adapter_id !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}$/u.test(fence.adapter_id) || typeof fence.host_id !== "string" || !fence.host_id || fence.assignment_id !== null && (typeof fence.assignment_id !== "string" || !fence.assignment_id) || typeof fence.failure_category !== "string" || !/^[a-z0-9][a-z0-9._-]{0,159}$/u.test(fence.failure_category) || typeof fence.failure_code !== "string" || !/^[a-z0-9][a-z0-9._-]{0,159}$/u.test(fence.failure_code) || !["not_dispatched", "confirmed_dispatched", "outcome_unknown"].includes(
|
|
19922
|
+
String(fence.dispatch_outcome)
|
|
19923
|
+
) || fence.retry_at !== null && !isIsoTimestamp(fence.retry_at) || !isIsoTimestamp(fence.created_at)) throw new Error(message);
|
|
19924
|
+
return fence;
|
|
19925
|
+
};
|
|
19926
|
+
assertInferenceAgentRuntimeState = (value) => {
|
|
19927
|
+
const message = "Inference Agent runtime recovery state is invalid.";
|
|
19799
19928
|
const state = assertPlainObject(value, message);
|
|
19929
|
+
const generic = state.schema_version === "vtx_inference_agent_runtime_v3";
|
|
19800
19930
|
if (!hasExactKeys(state, [
|
|
19801
19931
|
"schema_version",
|
|
19932
|
+
...generic ? ["adapter_id"] : [],
|
|
19802
19933
|
"host_id",
|
|
19803
19934
|
"assignment",
|
|
19804
19935
|
"thread",
|
|
@@ -19807,9 +19938,13 @@ var init_agent_state = __esm({
|
|
|
19807
19938
|
"updated_at"
|
|
19808
19939
|
])) throw new Error(message);
|
|
19809
19940
|
const assignment = assertPlainObject(state.assignment, message);
|
|
19810
|
-
if (![
|
|
19941
|
+
if (![
|
|
19942
|
+
"vtx_codex_agent_runtime_v1",
|
|
19943
|
+
"vtx_codex_agent_runtime_v2",
|
|
19944
|
+
"vtx_inference_agent_runtime_v3"
|
|
19945
|
+
].includes(
|
|
19811
19946
|
String(state.schema_version)
|
|
19812
|
-
) || typeof state.host_id !== "string" || !state.host_id || !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at) || !hasExactKeys(
|
|
19947
|
+
) || generic && (typeof state.adapter_id !== "string" || !/^[a-z0-9][a-z0-9._-]{0,63}$/u.test(state.adapter_id)) || typeof state.host_id !== "string" || !state.host_id || !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at) || !hasExactKeys(
|
|
19813
19948
|
assignment,
|
|
19814
19949
|
[
|
|
19815
19950
|
"assignment_id",
|
|
@@ -19823,10 +19958,10 @@ var init_agent_state = __esm({
|
|
|
19823
19958
|
"minimum_wake_seconds",
|
|
19824
19959
|
"maximum_wake_seconds",
|
|
19825
19960
|
"lease_expires_at",
|
|
19826
|
-
...state.schema_version
|
|
19961
|
+
...state.schema_version !== "vtx_codex_agent_runtime_v1" ? ["data_contract"] : []
|
|
19827
19962
|
]
|
|
19828
19963
|
) || typeof assignment.assignment_id !== "string" || !assignment.assignment_id || !Number.isSafeInteger(assignment.assignment_generation) || Number(assignment.assignment_generation) < 1 || typeof assignment.model_id !== "string" || !assignment.model_id || typeof assignment.reasoning_effort !== "string" || !assignment.reasoning_effort || !["trader", "assistant"].includes(String(assignment.bot_mode)) || !["server", "client"].includes(String(assignment.execution_mode)) || !Array.isArray(assignment.allowed_symbols) || assignment.allowed_symbols.some((symbol2) => typeof symbol2 !== "string" || !symbol2) || !assignment.output_schema || typeof assignment.output_schema !== "object" || Array.isArray(assignment.output_schema) || !Number.isSafeInteger(assignment.minimum_wake_seconds) || Number(assignment.minimum_wake_seconds) < 1 || !Number.isSafeInteger(assignment.maximum_wake_seconds) || Number(assignment.maximum_wake_seconds) < Number(assignment.minimum_wake_seconds) || !isIsoTimestamp(assignment.lease_expires_at)) throw new Error(message);
|
|
19829
|
-
if (state.schema_version
|
|
19964
|
+
if (state.schema_version !== "vtx_codex_agent_runtime_v1") {
|
|
19830
19965
|
if (!Array.isArray(assignment.data_contract) || assignment.data_contract.length === 0) {
|
|
19831
19966
|
throw new Error(message);
|
|
19832
19967
|
}
|
|
@@ -19865,6 +20000,76 @@ var init_agent_state = __esm({
|
|
|
19865
20000
|
}
|
|
19866
20001
|
return state;
|
|
19867
20002
|
};
|
|
20003
|
+
readCodexAgentRuntimeState = readInferenceAgentRuntimeState;
|
|
20004
|
+
clearCodexAgentRuntimeState = clearInferenceAgentRuntimeState;
|
|
20005
|
+
foregroundAgentControlStatePath = (statePath) => `${statePath}.foreground-agent-control.json`;
|
|
20006
|
+
assertRuntimeAssignment = (value, message) => {
|
|
20007
|
+
const assignment = assertPlainObject(value, message);
|
|
20008
|
+
if (!hasExactKeys(assignment, [
|
|
20009
|
+
"assignment_id",
|
|
20010
|
+
"assignment_generation",
|
|
20011
|
+
"model_id",
|
|
20012
|
+
"reasoning_effort",
|
|
20013
|
+
"bot_mode",
|
|
20014
|
+
"execution_mode",
|
|
20015
|
+
"allowed_symbols",
|
|
20016
|
+
"output_schema",
|
|
20017
|
+
"data_contract",
|
|
20018
|
+
"minimum_wake_seconds",
|
|
20019
|
+
"maximum_wake_seconds",
|
|
20020
|
+
"lease_expires_at"
|
|
20021
|
+
]) || typeof assignment.assignment_id !== "string" || !assignment.assignment_id || !Number.isSafeInteger(assignment.assignment_generation) || Number(assignment.assignment_generation) < 1 || typeof assignment.model_id !== "string" || !assignment.model_id || typeof assignment.reasoning_effort !== "string" || !assignment.reasoning_effort || !["trader", "assistant"].includes(String(assignment.bot_mode)) || !["server", "client"].includes(String(assignment.execution_mode)) || !Array.isArray(assignment.allowed_symbols) || assignment.allowed_symbols.some((symbol2) => typeof symbol2 !== "string" || !symbol2) || !assignment.output_schema || typeof assignment.output_schema !== "object" || Array.isArray(assignment.output_schema) || !Array.isArray(assignment.data_contract) || assignment.data_contract.length === 0 || !Number.isSafeInteger(assignment.minimum_wake_seconds) || Number(assignment.minimum_wake_seconds) < 1 || !Number.isSafeInteger(assignment.maximum_wake_seconds) || Number(assignment.maximum_wake_seconds) < Number(assignment.minimum_wake_seconds) || !isIsoTimestamp(assignment.lease_expires_at)) throw new Error(message);
|
|
20022
|
+
const ids = assignment.data_contract.map((value2) => {
|
|
20023
|
+
const descriptor = assertPlainObject(value2, message);
|
|
20024
|
+
if (!hasExactKeys(descriptor, [
|
|
20025
|
+
"id",
|
|
20026
|
+
"title",
|
|
20027
|
+
"description",
|
|
20028
|
+
"input_schema",
|
|
20029
|
+
"input_schema_sha256"
|
|
20030
|
+
]) || typeof descriptor.id !== "string" || !descriptor.id || typeof descriptor.title !== "string" || !descriptor.title || typeof descriptor.description !== "string" || !descriptor.description || !descriptor.input_schema || typeof descriptor.input_schema !== "object" || Array.isArray(descriptor.input_schema) || typeof descriptor.input_schema_sha256 !== "string" || !/^[0-9a-f]{64}$/u.test(descriptor.input_schema_sha256)) throw new Error(message);
|
|
20031
|
+
return descriptor.id;
|
|
20032
|
+
});
|
|
20033
|
+
if (new Set(ids).size !== ids.length) throw new Error(message);
|
|
20034
|
+
return assignment;
|
|
20035
|
+
};
|
|
20036
|
+
assertForegroundAgentControlState = (value) => {
|
|
20037
|
+
const message = "Foreground Agent control recovery state is invalid.";
|
|
20038
|
+
const state = assertPlainObject(value, message);
|
|
20039
|
+
if (!hasExactKeys(state, [
|
|
20040
|
+
"schema_version",
|
|
20041
|
+
"host_id",
|
|
20042
|
+
"assignment",
|
|
20043
|
+
"pending_next",
|
|
20044
|
+
"pending_decision",
|
|
20045
|
+
"next_wake_at",
|
|
20046
|
+
"updated_at"
|
|
20047
|
+
]) || state.schema_version !== "vtx_foreground_agent_control_v1" || typeof state.host_id !== "string" || !state.host_id || state.next_wake_at !== null && !isIsoTimestamp(state.next_wake_at) || !isIsoTimestamp(state.updated_at)) throw new Error(message);
|
|
20048
|
+
if (state.assignment !== null) assertRuntimeAssignment(state.assignment, message);
|
|
20049
|
+
if (state.pending_next !== null) {
|
|
20050
|
+
const pending = assertPlainObject(state.pending_next, message);
|
|
20051
|
+
if (!hasExactKeys(pending, ["operation_id", "requested_at"]) || typeof pending.operation_id !== "string" || !pending.operation_id || !isIsoTimestamp(pending.requested_at)) throw new Error(message);
|
|
20052
|
+
}
|
|
20053
|
+
if (state.pending_decision !== null) {
|
|
20054
|
+
if (state.assignment === null) throw new Error(message);
|
|
20055
|
+
const pending = assertPlainObject(state.pending_decision, message);
|
|
20056
|
+
if (!hasExactKeys(pending, [
|
|
20057
|
+
"request",
|
|
20058
|
+
"first_transmit_at",
|
|
20059
|
+
"last_status_check_at"
|
|
20060
|
+
])) throw new Error(message);
|
|
20061
|
+
const request = assertPlainObject(pending.request, message);
|
|
20062
|
+
if (!hasExactKeys(request, [
|
|
20063
|
+
"assignment_id",
|
|
20064
|
+
"assignment_generation",
|
|
20065
|
+
"operation_id",
|
|
20066
|
+
"candidate",
|
|
20067
|
+
"observed_at",
|
|
20068
|
+
"provenance"
|
|
20069
|
+
]) || request.assignment_id !== state.assignment.assignment_id || request.assignment_generation !== state.assignment.assignment_generation || typeof request.operation_id !== "string" || !request.operation_id || !request.candidate || typeof request.candidate !== "object" || Array.isArray(request.candidate) || !isIsoTimestamp(request.observed_at) || !request.provenance || typeof request.provenance !== "object" || Array.isArray(request.provenance) || pending.first_transmit_at !== null && !isIsoTimestamp(pending.first_transmit_at) || pending.last_status_check_at !== null && !isIsoTimestamp(pending.last_status_check_at)) throw new Error(message);
|
|
20070
|
+
}
|
|
20071
|
+
return state;
|
|
20072
|
+
};
|
|
19868
20073
|
assertNextState = (value) => {
|
|
19869
20074
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
19870
20075
|
throw new Error("Agent-driven inference next recovery state is invalid.");
|
|
@@ -24019,15 +24224,17 @@ $items = @(Get-CimInstance Win32_Process | Where-Object { $_.Name -in @('node.ex
|
|
|
24019
24224
|
});
|
|
24020
24225
|
|
|
24021
24226
|
// lib/inference-host/copilot-adapter.ts
|
|
24227
|
+
import { randomUUID } from "node:crypto";
|
|
24022
24228
|
import { mkdtemp as mkdtemp2, rm as rm4 } from "node:fs/promises";
|
|
24023
24229
|
import { createRequire as createRequire2 } from "node:module";
|
|
24024
24230
|
import { tmpdir as tmpdir3 } from "node:os";
|
|
24025
24231
|
import { join as join5 } from "node:path";
|
|
24026
24232
|
import {
|
|
24027
24233
|
CopilotClient,
|
|
24028
|
-
RuntimeConnection
|
|
24234
|
+
RuntimeConnection,
|
|
24235
|
+
defineTool
|
|
24029
24236
|
} from "@github/copilot-sdk";
|
|
24030
|
-
var COPILOT_SDK_VERSION, MAX_RESULT_BYTES, resolveRuntimePackage, copilotRuntimePackageCandidates, resolvePinnedCopilotCliPath, createPrivateWorkspace, cleanCopilotEnvironment, defaultClient, modelCapabilities, requiredUsageInteger, optionalUsageInteger, CopilotSubscriptionAdapter;
|
|
24237
|
+
var COPILOT_SDK_VERSION, MAX_RESULT_BYTES, resolveRuntimePackage, copilotRuntimePackageCandidates, resolvePinnedCopilotCliPath, createPrivateWorkspace, cleanCopilotEnvironment, defaultClient, modelCapabilities, requiredUsageInteger, optionalUsageInteger, copilotAgentToolDefinitions, CopilotSubscriptionAdapter;
|
|
24031
24238
|
var init_copilot_adapter = __esm({
|
|
24032
24239
|
"lib/inference-host/copilot-adapter.ts"() {
|
|
24033
24240
|
"use strict";
|
|
@@ -24123,9 +24330,66 @@ var init_copilot_adapter = __esm({
|
|
|
24123
24330
|
}
|
|
24124
24331
|
return Number(value);
|
|
24125
24332
|
};
|
|
24333
|
+
copilotAgentToolDefinitions = (input, evidence) => {
|
|
24334
|
+
const execute = async (tool, argumentsValue) => {
|
|
24335
|
+
const argumentsRecord = argumentsValue && typeof argumentsValue === "object" && !Array.isArray(argumentsValue) ? argumentsValue : {};
|
|
24336
|
+
const callId = randomUUID();
|
|
24337
|
+
const result2 = await input.executeTool({
|
|
24338
|
+
callId,
|
|
24339
|
+
tool,
|
|
24340
|
+
arguments: argumentsRecord
|
|
24341
|
+
});
|
|
24342
|
+
evidence.push({ callId, tool, arguments: argumentsRecord, success: result2.success });
|
|
24343
|
+
return result2.success ? result2.value : { error: result2.value };
|
|
24344
|
+
};
|
|
24345
|
+
return [
|
|
24346
|
+
defineTool("vtx_get_data", {
|
|
24347
|
+
description: "Request assignment-scoped VTX data using one exact canonical capability schema.",
|
|
24348
|
+
parameters: {
|
|
24349
|
+
oneOf: input.dataContract.map((descriptor) => ({
|
|
24350
|
+
type: "object",
|
|
24351
|
+
additionalProperties: false,
|
|
24352
|
+
required: ["capability", "arguments"],
|
|
24353
|
+
description: descriptor.description,
|
|
24354
|
+
properties: {
|
|
24355
|
+
capability: { type: "string", const: descriptor.id, title: descriptor.title },
|
|
24356
|
+
arguments: descriptor.input_schema
|
|
24357
|
+
}
|
|
24358
|
+
}))
|
|
24359
|
+
},
|
|
24360
|
+
skipPermission: true,
|
|
24361
|
+
handler: async (args) => await execute("vtx_get_data", args)
|
|
24362
|
+
}),
|
|
24363
|
+
defineTool("vtx_submit_decision", {
|
|
24364
|
+
description: "Submit one VTX structured trading decision candidate.",
|
|
24365
|
+
parameters: {
|
|
24366
|
+
type: "object",
|
|
24367
|
+
additionalProperties: false,
|
|
24368
|
+
required: ["candidate"],
|
|
24369
|
+
properties: { candidate: input.decisionSchema }
|
|
24370
|
+
},
|
|
24371
|
+
skipPermission: true,
|
|
24372
|
+
handler: async (args) => await execute("vtx_submit_decision", args)
|
|
24373
|
+
}),
|
|
24374
|
+
defineTool("vtx_decision_status", {
|
|
24375
|
+
description: "Resolve the durable status of a previously attempted decision operation.",
|
|
24376
|
+
parameters: {
|
|
24377
|
+
type: "object",
|
|
24378
|
+
additionalProperties: false,
|
|
24379
|
+
required: ["operation_id"],
|
|
24380
|
+
properties: { operation_id: { type: "string", minLength: 1 } }
|
|
24381
|
+
},
|
|
24382
|
+
skipPermission: true,
|
|
24383
|
+
handler: async (args) => await execute("vtx_decision_status", args)
|
|
24384
|
+
})
|
|
24385
|
+
];
|
|
24386
|
+
};
|
|
24126
24387
|
CopilotSubscriptionAdapter = class {
|
|
24127
24388
|
constructor(dependencies = {}) {
|
|
24128
24389
|
this.inFlight = /* @__PURE__ */ new Map();
|
|
24390
|
+
this.agentConnection = null;
|
|
24391
|
+
this.agentWorkspaceCleanups = /* @__PURE__ */ new Map();
|
|
24392
|
+
this.closing = false;
|
|
24129
24393
|
this.dependencies = dependencies;
|
|
24130
24394
|
}
|
|
24131
24395
|
async preflight(signal) {
|
|
@@ -24337,6 +24601,1213 @@ ${input.outputSchemaJson}`
|
|
|
24337
24601
|
await workspace.cleanup();
|
|
24338
24602
|
}
|
|
24339
24603
|
}
|
|
24604
|
+
async runTurn(input) {
|
|
24605
|
+
if (this.closing) {
|
|
24606
|
+
throw new CodexAppServerError({
|
|
24607
|
+
message: "Copilot Agent adapter is closing.",
|
|
24608
|
+
category: "transport",
|
|
24609
|
+
code: "transport_closed",
|
|
24610
|
+
retryable: true
|
|
24611
|
+
});
|
|
24612
|
+
}
|
|
24613
|
+
input.signal?.throwIfAborted();
|
|
24614
|
+
if (Date.now() >= input.deadlineAtMs || input.dataContract.length === 0) {
|
|
24615
|
+
throw new CodexAppServerError({
|
|
24616
|
+
message: "Copilot Agent turn input is invalid or expired.",
|
|
24617
|
+
category: Date.now() >= input.deadlineAtMs ? "timeout" : "schema",
|
|
24618
|
+
code: Date.now() >= input.deadlineAtMs ? "deadline_exceeded" : "invalid_agent_turn_input",
|
|
24619
|
+
retryable: false
|
|
24620
|
+
});
|
|
24621
|
+
}
|
|
24622
|
+
const startedAt = (this.dependencies.now ?? Date.now)();
|
|
24623
|
+
const ownedWorkspace = input.durableThread ? null : await (this.dependencies.createAgentWorkspace ?? this.dependencies.createWorkspace ?? createPrivateWorkspace)();
|
|
24624
|
+
const workspacePath = input.durableThread?.threadPath ?? ownedWorkspace.path;
|
|
24625
|
+
if (ownedWorkspace) this.agentWorkspaceCleanups.set(workspacePath, ownedWorkspace.cleanup);
|
|
24626
|
+
const client = (this.dependencies.createClient ?? defaultClient)(workspacePath);
|
|
24627
|
+
let session = null;
|
|
24628
|
+
let durableCheckpointed = input.durableThread !== null;
|
|
24629
|
+
let dispatchEntered = false;
|
|
24630
|
+
const toolEvidence = [];
|
|
24631
|
+
try {
|
|
24632
|
+
await client.start();
|
|
24633
|
+
const tools = copilotAgentToolDefinitions(input, toolEvidence);
|
|
24634
|
+
const sessionConfig = {
|
|
24635
|
+
clientName: "@vtxmacro/cli durable Copilot Agent host",
|
|
24636
|
+
model: input.requestedModel,
|
|
24637
|
+
...input.requestedReasoningEffort === "none" ? {} : { reasoningEffort: input.requestedReasoningEffort },
|
|
24638
|
+
systemMessage: {
|
|
24639
|
+
mode: "replace",
|
|
24640
|
+
content: `${input.systemPrompt}
|
|
24641
|
+
|
|
24642
|
+
Return only one JSON value matching this JSON Schema exactly:
|
|
24643
|
+
${JSON.stringify(input.outputSchema)}`
|
|
24644
|
+
},
|
|
24645
|
+
tools,
|
|
24646
|
+
availableTools: tools.map((tool) => tool.name),
|
|
24647
|
+
enableConfigDiscovery: false,
|
|
24648
|
+
streaming: true,
|
|
24649
|
+
workingDirectory: workspacePath,
|
|
24650
|
+
infiniteSessions: { enabled: true }
|
|
24651
|
+
};
|
|
24652
|
+
session = input.durableThread ? await client.resumeSession(input.durableThread.threadId, sessionConfig) : await client.createSession(sessionConfig);
|
|
24653
|
+
this.agentConnection = {
|
|
24654
|
+
client,
|
|
24655
|
+
session,
|
|
24656
|
+
workspacePath,
|
|
24657
|
+
cleanup: ownedWorkspace?.cleanup ?? null
|
|
24658
|
+
};
|
|
24659
|
+
const thread = {
|
|
24660
|
+
threadId: session.sessionId,
|
|
24661
|
+
threadPath: workspacePath,
|
|
24662
|
+
effectiveModel: input.requestedModel,
|
|
24663
|
+
effectiveReasoningEffort: input.requestedReasoningEffort
|
|
24664
|
+
};
|
|
24665
|
+
if (input.onThreadReady) {
|
|
24666
|
+
await input.onThreadReady(thread);
|
|
24667
|
+
durableCheckpointed = true;
|
|
24668
|
+
}
|
|
24669
|
+
const usageEvents = [];
|
|
24670
|
+
session.on((event) => {
|
|
24671
|
+
if (event.type === "assistant.usage" && !event.agentId) usageEvents.push(event);
|
|
24672
|
+
});
|
|
24673
|
+
const onAbort = () => {
|
|
24674
|
+
void session?.abort().catch(() => void 0);
|
|
24675
|
+
};
|
|
24676
|
+
input.signal?.addEventListener("abort", onAbort, { once: true });
|
|
24677
|
+
dispatchEntered = true;
|
|
24678
|
+
let response;
|
|
24679
|
+
try {
|
|
24680
|
+
response = await session.sendAndWait(
|
|
24681
|
+
{ prompt: input.userPrompt },
|
|
24682
|
+
Math.max(1, input.deadlineAtMs - Date.now())
|
|
24683
|
+
);
|
|
24684
|
+
} finally {
|
|
24685
|
+
input.signal?.removeEventListener("abort", onAbort);
|
|
24686
|
+
}
|
|
24687
|
+
if (!response?.data.content || Buffer.byteLength(response.data.content, "utf8") > MAX_RESULT_BYTES) {
|
|
24688
|
+
throw new Error("copilot_agent_invalid_result");
|
|
24689
|
+
}
|
|
24690
|
+
const observedModels = /* @__PURE__ */ new Set();
|
|
24691
|
+
const observedEfforts = /* @__PURE__ */ new Set();
|
|
24692
|
+
let inputTokens = 0;
|
|
24693
|
+
let cachedInputTokens = 0;
|
|
24694
|
+
let outputTokens = 0;
|
|
24695
|
+
let reasoningOutputTokens = 0;
|
|
24696
|
+
let cacheWriteInputTokens = 0;
|
|
24697
|
+
let cacheWriteSupported = false;
|
|
24698
|
+
let timeToFirstTokenMs = null;
|
|
24699
|
+
let providerCallId = null;
|
|
24700
|
+
for (const event of usageEvents) {
|
|
24701
|
+
if (event.type !== "assistant.usage") continue;
|
|
24702
|
+
observedModels.add(event.data.model);
|
|
24703
|
+
if (event.data.reasoningEffort) observedEfforts.add(event.data.reasoningEffort);
|
|
24704
|
+
inputTokens += requiredUsageInteger(event.data.inputTokens, "input_tokens");
|
|
24705
|
+
cachedInputTokens += optionalUsageInteger(event.data.cacheReadTokens, "cache_read_tokens");
|
|
24706
|
+
outputTokens += requiredUsageInteger(event.data.outputTokens, "output_tokens");
|
|
24707
|
+
reasoningOutputTokens += optionalUsageInteger(event.data.reasoningTokens, "reasoning_tokens");
|
|
24708
|
+
if (event.data.cacheWriteTokens !== void 0) {
|
|
24709
|
+
cacheWriteSupported = true;
|
|
24710
|
+
cacheWriteInputTokens += optionalUsageInteger(event.data.cacheWriteTokens, "cache_write_tokens");
|
|
24711
|
+
}
|
|
24712
|
+
if (timeToFirstTokenMs === null && Number.isSafeInteger(event.data.timeToFirstTokenMs)) {
|
|
24713
|
+
timeToFirstTokenMs = Number(event.data.timeToFirstTokenMs);
|
|
24714
|
+
}
|
|
24715
|
+
providerCallId = event.data.providerCallId ?? event.data.apiCallId ?? providerCallId;
|
|
24716
|
+
}
|
|
24717
|
+
if (usageEvents.length === 0) throw new Error("copilot_agent_usage_receipt_missing");
|
|
24718
|
+
if (response.data.model) observedModels.add(response.data.model);
|
|
24719
|
+
if (observedModels.size !== 1 || !observedModels.has(input.requestedModel)) {
|
|
24720
|
+
throw new Error("copilot_agent_effective_model_mismatch");
|
|
24721
|
+
}
|
|
24722
|
+
const effectiveEffort = input.requestedReasoningEffort === "none" ? observedEfforts.size === 0 ? "none" : observedEfforts.size === 1 ? [...observedEfforts][0] : null : observedEfforts.size === 1 ? [...observedEfforts][0] : null;
|
|
24723
|
+
if (effectiveEffort !== input.requestedReasoningEffort) {
|
|
24724
|
+
throw new Error("copilot_agent_effective_effort_mismatch");
|
|
24725
|
+
}
|
|
24726
|
+
const usage = {
|
|
24727
|
+
inputTokens,
|
|
24728
|
+
cachedInputTokens: Math.min(cachedInputTokens, inputTokens),
|
|
24729
|
+
outputTokens,
|
|
24730
|
+
reasoningOutputTokens: Math.min(reasoningOutputTokens, outputTokens),
|
|
24731
|
+
totalTokens: inputTokens + outputTokens,
|
|
24732
|
+
cacheWriteInputTokens: cacheWriteSupported ? cacheWriteInputTokens : null,
|
|
24733
|
+
cacheWriteSupported
|
|
24734
|
+
};
|
|
24735
|
+
return {
|
|
24736
|
+
thread,
|
|
24737
|
+
turn: {
|
|
24738
|
+
text: response.data.content,
|
|
24739
|
+
reasoningContent: response.data.reasoningText ?? null,
|
|
24740
|
+
reasoningSummary: null,
|
|
24741
|
+
requestedModel: input.requestedModel,
|
|
24742
|
+
effectiveModel: input.requestedModel,
|
|
24743
|
+
requestedReasoningEffort: input.requestedReasoningEffort,
|
|
24744
|
+
effectiveReasoningEffort: effectiveEffort,
|
|
24745
|
+
adapterRequestId: providerCallId ?? response.data.requestId ?? response.data.messageId,
|
|
24746
|
+
adapterResponseId: response.data.serviceRequestId ?? response.data.messageId,
|
|
24747
|
+
usage,
|
|
24748
|
+
latencyMs: Math.max(0, (this.dependencies.now ?? Date.now)() - startedAt),
|
|
24749
|
+
timeToFirstTokenMs,
|
|
24750
|
+
terminalStatus: "completed",
|
|
24751
|
+
toolCalls: toolEvidence,
|
|
24752
|
+
webSearches: []
|
|
24753
|
+
}
|
|
24754
|
+
};
|
|
24755
|
+
} catch (error48) {
|
|
24756
|
+
if (error48 instanceof CodexAppServerError) throw error48;
|
|
24757
|
+
const cancelled = input.signal?.aborted === true;
|
|
24758
|
+
const deadline = Date.now() >= input.deadlineAtMs;
|
|
24759
|
+
if (dispatchEntered) await session?.abort().catch(() => void 0);
|
|
24760
|
+
if (session && !durableCheckpointed) {
|
|
24761
|
+
const abandonedSession = session;
|
|
24762
|
+
session = null;
|
|
24763
|
+
if (this.agentConnection?.session === abandonedSession) this.agentConnection = null;
|
|
24764
|
+
await abandonedSession.disconnect().catch(() => void 0);
|
|
24765
|
+
await client.deleteSession(abandonedSession.sessionId).catch(() => void 0);
|
|
24766
|
+
const cleanup = this.agentWorkspaceCleanups.get(workspacePath);
|
|
24767
|
+
if (cleanup) {
|
|
24768
|
+
await cleanup().catch(() => void 0);
|
|
24769
|
+
this.agentWorkspaceCleanups.delete(workspacePath);
|
|
24770
|
+
}
|
|
24771
|
+
}
|
|
24772
|
+
throw new CodexAppServerError({
|
|
24773
|
+
message: cancelled ? "Copilot Agent turn was cancelled." : deadline ? "Copilot Agent turn exceeded its deadline." : error48 instanceof Error ? error48.message : "Copilot Agent adapter failed.",
|
|
24774
|
+
category: cancelled ? "cancelled" : deadline ? "timeout" : "adapter",
|
|
24775
|
+
code: cancelled ? "cancelled" : deadline ? "deadline_exceeded" : "copilot_agent_adapter_failure",
|
|
24776
|
+
retryable: false,
|
|
24777
|
+
dispatchOutcome: dispatchEntered ? "confirmed_dispatched" : "not_dispatched",
|
|
24778
|
+
cause: error48
|
|
24779
|
+
});
|
|
24780
|
+
} finally {
|
|
24781
|
+
await session?.disconnect().catch(() => void 0);
|
|
24782
|
+
await client.stop().catch(async () => {
|
|
24783
|
+
await client.forceStop();
|
|
24784
|
+
});
|
|
24785
|
+
if (this.agentConnection?.session === session) this.agentConnection = null;
|
|
24786
|
+
}
|
|
24787
|
+
}
|
|
24788
|
+
async releaseThread(thread) {
|
|
24789
|
+
const active = this.agentConnection;
|
|
24790
|
+
if (active?.session.sessionId === thread.threadId) {
|
|
24791
|
+
await active.session.disconnect().catch(() => void 0);
|
|
24792
|
+
await active.client.stop().catch(async () => {
|
|
24793
|
+
await active.client.forceStop();
|
|
24794
|
+
});
|
|
24795
|
+
this.agentConnection = null;
|
|
24796
|
+
}
|
|
24797
|
+
const client = (this.dependencies.createClient ?? defaultClient)(thread.threadPath);
|
|
24798
|
+
await client.start();
|
|
24799
|
+
try {
|
|
24800
|
+
await client.deleteSession(thread.threadId);
|
|
24801
|
+
} finally {
|
|
24802
|
+
await client.stop().catch(async () => {
|
|
24803
|
+
await client.forceStop();
|
|
24804
|
+
});
|
|
24805
|
+
}
|
|
24806
|
+
const cleanup = this.agentWorkspaceCleanups.get(thread.threadPath);
|
|
24807
|
+
if (cleanup) {
|
|
24808
|
+
await cleanup();
|
|
24809
|
+
this.agentWorkspaceCleanups.delete(thread.threadPath);
|
|
24810
|
+
}
|
|
24811
|
+
}
|
|
24812
|
+
async close() {
|
|
24813
|
+
this.closing = true;
|
|
24814
|
+
const active = this.agentConnection;
|
|
24815
|
+
this.agentConnection = null;
|
|
24816
|
+
if (!active) return;
|
|
24817
|
+
await active.session.disconnect().catch(() => void 0);
|
|
24818
|
+
await active.client.stop().catch(async () => {
|
|
24819
|
+
await active.client.forceStop();
|
|
24820
|
+
});
|
|
24821
|
+
}
|
|
24822
|
+
};
|
|
24823
|
+
}
|
|
24824
|
+
});
|
|
24825
|
+
|
|
24826
|
+
// lib/inference-host/deepseek-transport-proxy.ts
|
|
24827
|
+
import { createServer as createServer2 } from "node:http";
|
|
24828
|
+
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
24829
|
+
var MAX_REQUEST_BYTES, DeepSeekTransportProxy;
|
|
24830
|
+
var init_deepseek_transport_proxy = __esm({
|
|
24831
|
+
"lib/inference-host/deepseek-transport-proxy.ts"() {
|
|
24832
|
+
"use strict";
|
|
24833
|
+
MAX_REQUEST_BYTES = 8 * 1024 * 1024;
|
|
24834
|
+
DeepSeekTransportProxy = class {
|
|
24835
|
+
constructor(apiKey, expectedModel, expectedEffort, upstreamBaseUrl = "https://api.deepseek.com", fetchImpl = fetch) {
|
|
24836
|
+
this.apiKey = apiKey;
|
|
24837
|
+
this.expectedModel = expectedModel;
|
|
24838
|
+
this.expectedEffort = expectedEffort;
|
|
24839
|
+
this.upstreamBaseUrl = upstreamBaseUrl;
|
|
24840
|
+
this.fetchImpl = fetchImpl;
|
|
24841
|
+
this.server = null;
|
|
24842
|
+
this.urlValue = null;
|
|
24843
|
+
this.receiptsValue = [];
|
|
24844
|
+
this.controllers = /* @__PURE__ */ new Set();
|
|
24845
|
+
this.token = randomBytes4(24).toString("hex");
|
|
24846
|
+
this.upstreamRequestStartedValue = false;
|
|
24847
|
+
this.providerResponseObservedValue = false;
|
|
24848
|
+
this.unansweredUpstreamRequestsValue = 0;
|
|
24849
|
+
}
|
|
24850
|
+
get baseUrl() {
|
|
24851
|
+
if (!this.urlValue) throw new Error("deepseek_transport_proxy_not_started");
|
|
24852
|
+
return `${this.urlValue}/${this.token}`;
|
|
24853
|
+
}
|
|
24854
|
+
get receipts() {
|
|
24855
|
+
return [...this.receiptsValue];
|
|
24856
|
+
}
|
|
24857
|
+
get providerResponseObserved() {
|
|
24858
|
+
return this.providerResponseObservedValue;
|
|
24859
|
+
}
|
|
24860
|
+
get upstreamRequestStarted() {
|
|
24861
|
+
return this.upstreamRequestStartedValue;
|
|
24862
|
+
}
|
|
24863
|
+
get unansweredUpstreamRequest() {
|
|
24864
|
+
return this.unansweredUpstreamRequestsValue > 0;
|
|
24865
|
+
}
|
|
24866
|
+
async start() {
|
|
24867
|
+
if (this.server) return;
|
|
24868
|
+
this.server = createServer2(async (request, response) => {
|
|
24869
|
+
try {
|
|
24870
|
+
const prefix = `/${this.token}`;
|
|
24871
|
+
const requestUrl = request.url ?? "";
|
|
24872
|
+
if (request.method !== "POST" || requestUrl !== `${prefix}/chat/completions`) {
|
|
24873
|
+
response.writeHead(404).end();
|
|
24874
|
+
return;
|
|
24875
|
+
}
|
|
24876
|
+
const chunks = [];
|
|
24877
|
+
let requestBytes = 0;
|
|
24878
|
+
for await (const chunk of request) {
|
|
24879
|
+
const buffer = Buffer.from(chunk);
|
|
24880
|
+
requestBytes += buffer.byteLength;
|
|
24881
|
+
if (requestBytes > MAX_REQUEST_BYTES) throw new Error("deepseek_proxy_request_too_large");
|
|
24882
|
+
chunks.push(buffer);
|
|
24883
|
+
}
|
|
24884
|
+
const body = Buffer.concat(chunks);
|
|
24885
|
+
let requestedModel = "";
|
|
24886
|
+
let requestedEffort = "off";
|
|
24887
|
+
const payload = JSON.parse(body.toString("utf8"));
|
|
24888
|
+
requestedModel = String(payload.model ?? "");
|
|
24889
|
+
const thinking = payload.thinking;
|
|
24890
|
+
requestedEffort = thinking?.type === "disabled" ? "off" : String(payload.reasoning_effort ?? "");
|
|
24891
|
+
if (requestedModel !== this.expectedModel || requestedEffort !== this.expectedEffort) throw new Error("deepseek_outbound_model_or_effort_mismatch");
|
|
24892
|
+
const controller = new AbortController();
|
|
24893
|
+
this.controllers.add(controller);
|
|
24894
|
+
try {
|
|
24895
|
+
this.upstreamRequestStartedValue = true;
|
|
24896
|
+
this.unansweredUpstreamRequestsValue += 1;
|
|
24897
|
+
const upstream = await this.fetchImpl(
|
|
24898
|
+
`${this.upstreamBaseUrl}/chat/completions`,
|
|
24899
|
+
{
|
|
24900
|
+
method: request.method,
|
|
24901
|
+
headers: {
|
|
24902
|
+
"authorization": `Bearer ${this.apiKey}`,
|
|
24903
|
+
"content-type": String(request.headers["content-type"] ?? "application/json"),
|
|
24904
|
+
"accept": String(request.headers.accept ?? "application/json"),
|
|
24905
|
+
"user-agent": String(request.headers["user-agent"] ?? "@vtxmacro/cli")
|
|
24906
|
+
},
|
|
24907
|
+
body,
|
|
24908
|
+
signal: controller.signal
|
|
24909
|
+
}
|
|
24910
|
+
);
|
|
24911
|
+
this.unansweredUpstreamRequestsValue -= 1;
|
|
24912
|
+
this.providerResponseObservedValue = true;
|
|
24913
|
+
const headers = {};
|
|
24914
|
+
upstream.headers.forEach((value, name) => {
|
|
24915
|
+
if (!["connection", "transfer-encoding", "content-length"].includes(name)) {
|
|
24916
|
+
headers[name] = value;
|
|
24917
|
+
}
|
|
24918
|
+
});
|
|
24919
|
+
response.writeHead(upstream.status, headers);
|
|
24920
|
+
if (!upstream.body) {
|
|
24921
|
+
response.end();
|
|
24922
|
+
return;
|
|
24923
|
+
}
|
|
24924
|
+
if (!upstream.ok) {
|
|
24925
|
+
const errorReader = upstream.body.getReader();
|
|
24926
|
+
while (true) {
|
|
24927
|
+
const part = await errorReader.read();
|
|
24928
|
+
if (part.done) break;
|
|
24929
|
+
response.write(Buffer.from(part.value));
|
|
24930
|
+
}
|
|
24931
|
+
response.end();
|
|
24932
|
+
return;
|
|
24933
|
+
}
|
|
24934
|
+
const reader = upstream.body.getReader();
|
|
24935
|
+
const decoder2 = new TextDecoder();
|
|
24936
|
+
let pending = "";
|
|
24937
|
+
let observedId = "";
|
|
24938
|
+
let terminalObserved = false;
|
|
24939
|
+
const forwardLine = (line) => {
|
|
24940
|
+
if (!line.startsWith("data:")) {
|
|
24941
|
+
response.write(`${line}
|
|
24942
|
+
`);
|
|
24943
|
+
return;
|
|
24944
|
+
}
|
|
24945
|
+
const value = line.slice(5).trim();
|
|
24946
|
+
if (!value) {
|
|
24947
|
+
response.write(`${line}
|
|
24948
|
+
`);
|
|
24949
|
+
return;
|
|
24950
|
+
}
|
|
24951
|
+
if (value === "[DONE]") {
|
|
24952
|
+
if (terminalObserved || !observedId) {
|
|
24953
|
+
throw new Error("deepseek_provider_receipt_missing_or_mismatched");
|
|
24954
|
+
}
|
|
24955
|
+
terminalObserved = true;
|
|
24956
|
+
this.receiptsValue.push({
|
|
24957
|
+
id: observedId,
|
|
24958
|
+
model: this.expectedModel,
|
|
24959
|
+
requestedModel,
|
|
24960
|
+
requestedReasoningEffort: requestedEffort
|
|
24961
|
+
});
|
|
24962
|
+
response.write(`${line}
|
|
24963
|
+
`);
|
|
24964
|
+
return;
|
|
24965
|
+
}
|
|
24966
|
+
const event = JSON.parse(value);
|
|
24967
|
+
const eventId = typeof event.id === "string" ? event.id.trim() : "";
|
|
24968
|
+
const eventModel = typeof event.model === "string" ? event.model.trim() : "";
|
|
24969
|
+
if (!eventId || eventModel !== this.expectedModel || observedId && eventId !== observedId) throw new Error("deepseek_provider_receipt_missing_or_mismatched");
|
|
24970
|
+
observedId = eventId;
|
|
24971
|
+
response.write(`${line}
|
|
24972
|
+
`);
|
|
24973
|
+
};
|
|
24974
|
+
while (true) {
|
|
24975
|
+
const part = await reader.read();
|
|
24976
|
+
if (part.done) break;
|
|
24977
|
+
pending += decoder2.decode(part.value, { stream: true });
|
|
24978
|
+
const lines = pending.split(/\r?\n/u);
|
|
24979
|
+
pending = lines.pop() ?? "";
|
|
24980
|
+
for (const line of lines) forwardLine(line);
|
|
24981
|
+
}
|
|
24982
|
+
pending += decoder2.decode();
|
|
24983
|
+
if (pending) forwardLine(pending);
|
|
24984
|
+
if (!terminalObserved) {
|
|
24985
|
+
throw new Error("deepseek_provider_receipt_missing_or_mismatched");
|
|
24986
|
+
}
|
|
24987
|
+
response.end();
|
|
24988
|
+
} finally {
|
|
24989
|
+
this.controllers.delete(controller);
|
|
24990
|
+
}
|
|
24991
|
+
} catch {
|
|
24992
|
+
if (!response.headersSent) response.writeHead(502);
|
|
24993
|
+
response.end();
|
|
24994
|
+
}
|
|
24995
|
+
});
|
|
24996
|
+
await new Promise((resolve6, reject) => {
|
|
24997
|
+
this.server.once("error", reject);
|
|
24998
|
+
this.server.listen(0, "127.0.0.1", () => resolve6());
|
|
24999
|
+
});
|
|
25000
|
+
const address = this.server.address();
|
|
25001
|
+
if (!address || typeof address === "string") throw new Error("deepseek_proxy_bind_failed");
|
|
25002
|
+
this.urlValue = `http://127.0.0.1:${address.port}`;
|
|
25003
|
+
}
|
|
25004
|
+
async close() {
|
|
25005
|
+
for (const controller of this.controllers) controller.abort();
|
|
25006
|
+
const server = this.server;
|
|
25007
|
+
this.server = null;
|
|
25008
|
+
this.urlValue = null;
|
|
25009
|
+
if (!server) return;
|
|
25010
|
+
await new Promise((resolve6) => server.close(() => resolve6()));
|
|
25011
|
+
}
|
|
25012
|
+
};
|
|
25013
|
+
}
|
|
25014
|
+
});
|
|
25015
|
+
|
|
25016
|
+
// lib/inference-host/deepseek-harness-adapter.ts
|
|
25017
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
25018
|
+
import { mkdtemp as mkdtemp3, realpath as realpath4, rm as rm5 } from "node:fs/promises";
|
|
25019
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
25020
|
+
import { basename, dirname as dirname4, join as join6 } from "node:path";
|
|
25021
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
25022
|
+
import * as AgentSpine from "@deepseek-ai/dsh-agent-spine-demo";
|
|
25023
|
+
import {
|
|
25024
|
+
createUserMessage,
|
|
25025
|
+
LlmError
|
|
25026
|
+
} from "@deepseek-ai/dsh-llm";
|
|
25027
|
+
import {
|
|
25028
|
+
DeepSeekAdapter,
|
|
25029
|
+
resolveAdapterOptions
|
|
25030
|
+
} from "@deepseek-ai/dsh-llm-deepseek";
|
|
25031
|
+
import * as LlmDeepSeek from "@deepseek-ai/dsh-llm-deepseek";
|
|
25032
|
+
import { SessionId } from "@deepseek-ai/dsh-session";
|
|
25033
|
+
import * as SessionCheckpointPolicy from "@deepseek-ai/dsh-session-checkpoint-policy";
|
|
25034
|
+
import { JsonlSessionPersistence } from "@deepseek-ai/dsh-session-persistence-jsonl";
|
|
25035
|
+
var DEEPSEEK_HARNESS_VERSION, MAX_RESULT_BYTES2, DEEPSEEK_MODELS, DEEPSEEK_API_BASE_URL, isSupportedNodeVersion, effortForHarness, supportedEfforts, toVtxUsage, sumUsage, textFromBlocks, validateText, createDeadlineBoundary, nonDispatchedError, proxyDispatchOutcome, mapDeepSeekFailure, createPrivateWorkspace2, directAdapter, normalizeJsonValue, DeepSeekHarnessAdapter;
|
|
25036
|
+
var init_deepseek_harness_adapter = __esm({
|
|
25037
|
+
"lib/inference-host/deepseek-harness-adapter.ts"() {
|
|
25038
|
+
"use strict";
|
|
25039
|
+
init_codex_app_server();
|
|
25040
|
+
init_deepseek_transport_proxy();
|
|
25041
|
+
DEEPSEEK_HARNESS_VERSION = "0.1.1-rc.2";
|
|
25042
|
+
MAX_RESULT_BYTES2 = 3e5;
|
|
25043
|
+
DEEPSEEK_MODELS = ["deepseek-v4-flash", "deepseek-v4-pro"];
|
|
25044
|
+
DEEPSEEK_API_BASE_URL = "https://api.deepseek.com";
|
|
25045
|
+
isSupportedNodeVersion = (version3) => {
|
|
25046
|
+
const [major, minor] = version3.replace(/^v/u, "").split(".").map(Number);
|
|
25047
|
+
return major === 22 && minor >= 19 || major >= 24;
|
|
25048
|
+
};
|
|
25049
|
+
effortForHarness = (effort) => {
|
|
25050
|
+
if (effort === "none") return "off";
|
|
25051
|
+
if (effort === "low" || effort === "high" || effort === "max") return effort;
|
|
25052
|
+
throw new Error(`deepseek_reasoning_effort_unsupported:${effort}`);
|
|
25053
|
+
};
|
|
25054
|
+
supportedEfforts = (model) => model === "deepseek-v4-pro" ? ["none", "high", "max"] : ["none", "low", "high", "max"];
|
|
25055
|
+
toVtxUsage = (usage) => {
|
|
25056
|
+
const cacheRead = usage.cacheReadTokens ?? 0;
|
|
25057
|
+
const cacheWrite = usage.cacheWriteTokens ?? 0;
|
|
25058
|
+
const inclusiveInput = usage.inputTokens + cacheRead + cacheWrite;
|
|
25059
|
+
return {
|
|
25060
|
+
inputTokens: inclusiveInput,
|
|
25061
|
+
cachedInputTokens: cacheRead,
|
|
25062
|
+
outputTokens: usage.outputTokens,
|
|
25063
|
+
reasoningOutputTokens: Math.min(usage.reasoningTokens ?? 0, usage.outputTokens),
|
|
25064
|
+
totalTokens: inclusiveInput + usage.outputTokens,
|
|
25065
|
+
cacheWriteInputTokens: usage.cacheWriteTokens ?? null,
|
|
25066
|
+
cacheWriteSupported: usage.cacheWriteTokens !== void 0
|
|
25067
|
+
};
|
|
25068
|
+
};
|
|
25069
|
+
sumUsage = (values) => toVtxUsage({
|
|
25070
|
+
inputTokens: values.reduce((sum, value) => sum + value.inputTokens, 0),
|
|
25071
|
+
outputTokens: values.reduce((sum, value) => sum + value.outputTokens, 0),
|
|
25072
|
+
cacheReadTokens: values.reduce((sum, value) => sum + (value.cacheReadTokens ?? 0), 0),
|
|
25073
|
+
cacheWriteTokens: values.some((value) => value.cacheWriteTokens !== void 0) ? values.reduce((sum, value) => sum + (value.cacheWriteTokens ?? 0), 0) : void 0,
|
|
25074
|
+
reasoningTokens: values.reduce((sum, value) => sum + (value.reasoningTokens ?? 0), 0)
|
|
25075
|
+
});
|
|
25076
|
+
textFromBlocks = (blocks, type) => blocks.flatMap((block) => block.type === type ? [block.text] : []).join("");
|
|
25077
|
+
validateText = (text, code) => {
|
|
25078
|
+
if (!text.trim() || Buffer.byteLength(text, "utf8") > MAX_RESULT_BYTES2) throw new Error(code);
|
|
25079
|
+
return text;
|
|
25080
|
+
};
|
|
25081
|
+
createDeadlineBoundary = (source, deadlineAtMs) => {
|
|
25082
|
+
const controller = new AbortController();
|
|
25083
|
+
const relayAbort = () => controller.abort(source?.reason);
|
|
25084
|
+
source?.addEventListener("abort", relayAbort, { once: true });
|
|
25085
|
+
if (source?.aborted) controller.abort(source.reason);
|
|
25086
|
+
const timeout = setTimeout(
|
|
25087
|
+
() => controller.abort(new Error("deadline_exceeded")),
|
|
25088
|
+
Math.max(1, deadlineAtMs - Date.now())
|
|
25089
|
+
);
|
|
25090
|
+
timeout.unref();
|
|
25091
|
+
return {
|
|
25092
|
+
signal: controller.signal,
|
|
25093
|
+
cleanup: () => {
|
|
25094
|
+
clearTimeout(timeout);
|
|
25095
|
+
source?.removeEventListener("abort", relayAbort);
|
|
25096
|
+
}
|
|
25097
|
+
};
|
|
25098
|
+
};
|
|
25099
|
+
nonDispatchedError = (message, category, code, retryable = false) => new CodexAppServerError({
|
|
25100
|
+
message,
|
|
25101
|
+
category,
|
|
25102
|
+
code,
|
|
25103
|
+
retryable,
|
|
25104
|
+
dispatchOutcome: "not_dispatched"
|
|
25105
|
+
});
|
|
25106
|
+
proxyDispatchOutcome = (proxy) => {
|
|
25107
|
+
if (proxy.unansweredUpstreamRequest) return "outcome_unknown";
|
|
25108
|
+
if (proxy.providerResponseObserved) return "confirmed_dispatched";
|
|
25109
|
+
return proxy.upstreamRequestStarted ? "outcome_unknown" : "not_dispatched";
|
|
25110
|
+
};
|
|
25111
|
+
mapDeepSeekFailure = (options) => {
|
|
25112
|
+
if (options.error instanceof CodexAppServerError) return options.error;
|
|
25113
|
+
if (options.cancelled || options.deadline) {
|
|
25114
|
+
return new CodexAppServerError({
|
|
25115
|
+
message: options.cancelled ? "DeepSeek Harness request was cancelled." : "DeepSeek Harness request exceeded its deadline.",
|
|
25116
|
+
category: options.cancelled ? "cancelled" : "timeout",
|
|
25117
|
+
code: options.cancelled ? "cancelled" : "deadline_exceeded",
|
|
25118
|
+
retryable: false,
|
|
25119
|
+
dispatchOutcome: options.dispatchOutcome,
|
|
25120
|
+
cause: options.error
|
|
25121
|
+
});
|
|
25122
|
+
}
|
|
25123
|
+
if (options.error instanceof LlmError) {
|
|
25124
|
+
const failure = options.error.failure;
|
|
25125
|
+
const auth = ["AUTH", "INVALID_CREDENTIAL", "MISSING_CREDENTIAL"].includes(failure.code);
|
|
25126
|
+
const quota = failure.code === "QUOTA" || failure.status === 402;
|
|
25127
|
+
const rateLimit = failure.code === "RATE_LIMIT";
|
|
25128
|
+
const clientError = failure.status !== void 0 && failure.status >= 400 && failure.status < 500;
|
|
25129
|
+
const model = !auth && !quota && !rateLimit && clientError || [
|
|
25130
|
+
"CONTEXT_WINDOW_EXCEEDED",
|
|
25131
|
+
"INVALID_REQUEST",
|
|
25132
|
+
"UNSUPPORTED_CONTENT",
|
|
25133
|
+
"UNSUPPORTED_REASONING_EFFORT"
|
|
25134
|
+
].includes(failure.code);
|
|
25135
|
+
const transport = [
|
|
25136
|
+
"EMPTY_RESPONSE",
|
|
25137
|
+
"MALFORMED_RESPONSE",
|
|
25138
|
+
"SERVER",
|
|
25139
|
+
"STREAM_CLOSED",
|
|
25140
|
+
"TIMEOUT",
|
|
25141
|
+
"TRANSPORT"
|
|
25142
|
+
].includes(failure.code) || failure.code.startsWith("HTTP_") && !clientError;
|
|
25143
|
+
const code = auth ? "deepseek_auth_failed" : quota ? "quota_exceeded" : rateLimit ? "provider_rate_limited" : model ? `deepseek_${failure.code.toLowerCase()}` : transport ? `deepseek_${failure.code.toLowerCase()}` : "deepseek_harness_adapter_failure";
|
|
25144
|
+
return new CodexAppServerError({
|
|
25145
|
+
message: failure.message,
|
|
25146
|
+
category: auth ? "auth" : model || quota || rateLimit ? "model" : transport ? "transport" : "adapter",
|
|
25147
|
+
code,
|
|
25148
|
+
retryable: transport && !quota,
|
|
25149
|
+
dispatchOutcome: options.dispatchOutcome,
|
|
25150
|
+
httpStatusCode: failure.status ?? null,
|
|
25151
|
+
retryAtMs: failure.providerRetryAfterMs === void 0 ? null : Date.now() + failure.providerRetryAfterMs,
|
|
25152
|
+
cause: options.error
|
|
25153
|
+
});
|
|
25154
|
+
}
|
|
25155
|
+
return new CodexAppServerError({
|
|
25156
|
+
message: options.error instanceof Error ? options.error.message : "DeepSeek Harness adapter failed.",
|
|
25157
|
+
category: "adapter",
|
|
25158
|
+
code: "deepseek_harness_adapter_failure",
|
|
25159
|
+
retryable: false,
|
|
25160
|
+
dispatchOutcome: options.dispatchOutcome,
|
|
25161
|
+
cause: options.error
|
|
25162
|
+
});
|
|
25163
|
+
};
|
|
25164
|
+
createPrivateWorkspace2 = async () => {
|
|
25165
|
+
const path = await mkdtemp3(join6(tmpdir4(), "vtx-deepseek-harness-"));
|
|
25166
|
+
return { path, cleanup: async () => {
|
|
25167
|
+
await rm5(path, { recursive: true, force: true });
|
|
25168
|
+
} };
|
|
25169
|
+
};
|
|
25170
|
+
directAdapter = (proxy, model, effort) => {
|
|
25171
|
+
const connection = resolveAdapterOptions({
|
|
25172
|
+
apiKeyEnv: "VTX_DSH_LOOPBACK_TOKEN",
|
|
25173
|
+
baseURL: proxy.baseUrl,
|
|
25174
|
+
reasoningEffort: effort,
|
|
25175
|
+
thinking: "enabled",
|
|
25176
|
+
models: [{ id: model }],
|
|
25177
|
+
retryPolicy: { mode: "normal", maxRetries: 0 }
|
|
25178
|
+
});
|
|
25179
|
+
return new DeepSeekAdapter({
|
|
25180
|
+
options: () => connection,
|
|
25181
|
+
resolveApiKey: async () => "vtx-loopback-only",
|
|
25182
|
+
resolveUserId: () => "vtx-macro"
|
|
25183
|
+
});
|
|
25184
|
+
};
|
|
25185
|
+
normalizeJsonValue = (value) => JSON.parse(JSON.stringify(value));
|
|
25186
|
+
DeepSeekHarnessAdapter = class {
|
|
25187
|
+
constructor(dependencies) {
|
|
25188
|
+
this.agentWorkspaces = /* @__PURE__ */ new Map();
|
|
25189
|
+
this.closing = false;
|
|
25190
|
+
this.dependencies = dependencies;
|
|
25191
|
+
}
|
|
25192
|
+
async preflight(signal) {
|
|
25193
|
+
if (!isSupportedNodeVersion(this.dependencies.nodeVersion ?? process.version)) {
|
|
25194
|
+
throw new CodexAppServerError({
|
|
25195
|
+
message: "DeepSeek Harness requires Node 22.19 or newer in the Node 22 line, or Node 24+.",
|
|
25196
|
+
category: "adapter",
|
|
25197
|
+
code: "deepseek_harness_node_version_unsupported",
|
|
25198
|
+
retryable: false
|
|
25199
|
+
});
|
|
25200
|
+
}
|
|
25201
|
+
const credential = await this.dependencies.credentialStore.read(signal);
|
|
25202
|
+
if (!credential) {
|
|
25203
|
+
throw new CodexAppServerError({
|
|
25204
|
+
message: "Import a DeepSeek API key with vtx inference-host deepseek-login first.",
|
|
25205
|
+
category: "auth",
|
|
25206
|
+
code: "deepseek_harness_credential_required",
|
|
25207
|
+
retryable: false
|
|
25208
|
+
});
|
|
25209
|
+
}
|
|
25210
|
+
const response = await (this.dependencies.fetch ?? fetch)(
|
|
25211
|
+
`${this.dependencies.apiBaseUrl ?? DEEPSEEK_API_BASE_URL}/models`,
|
|
25212
|
+
{ headers: { authorization: `Bearer ${credential.apiKey}` }, signal }
|
|
25213
|
+
);
|
|
25214
|
+
if (!response.ok) {
|
|
25215
|
+
throw new CodexAppServerError({
|
|
25216
|
+
message: `DeepSeek model catalog request failed with HTTP ${response.status}.`,
|
|
25217
|
+
category: response.status === 401 || response.status === 403 ? "auth" : "transport",
|
|
25218
|
+
code: "deepseek_harness_model_catalog_failed",
|
|
25219
|
+
retryable: false
|
|
25220
|
+
});
|
|
25221
|
+
}
|
|
25222
|
+
const payload = await response.json();
|
|
25223
|
+
const live = new Set((payload.data ?? []).map((item) => String(item.id ?? "")));
|
|
25224
|
+
const models = DEEPSEEK_MODELS.filter((model) => live.has(model));
|
|
25225
|
+
if (models.length === 0) {
|
|
25226
|
+
throw new CodexAppServerError({
|
|
25227
|
+
message: "DeepSeek returned no VTX-supported Harness models.",
|
|
25228
|
+
category: "model",
|
|
25229
|
+
code: "deepseek_harness_model_catalog_empty",
|
|
25230
|
+
retryable: false
|
|
25231
|
+
});
|
|
25232
|
+
}
|
|
25233
|
+
return {
|
|
25234
|
+
adapterId: "deepseek-harness",
|
|
25235
|
+
runtimeVersion: DEEPSEEK_HARNESS_VERSION,
|
|
25236
|
+
authenticatedAccountIdentity: null,
|
|
25237
|
+
authenticatedAccountEmail: null,
|
|
25238
|
+
authenticatedAccountPlan: null,
|
|
25239
|
+
modelCapabilities: models.map((model, index) => ({
|
|
25240
|
+
id: model,
|
|
25241
|
+
model,
|
|
25242
|
+
displayName: model === "deepseek-v4-flash" ? "DeepSeek V4 Flash" : "DeepSeek V4 Pro",
|
|
25243
|
+
hidden: false,
|
|
25244
|
+
supportedReasoningEfforts: [...supportedEfforts(model)],
|
|
25245
|
+
defaultReasoningEffort: "high",
|
|
25246
|
+
isDefault: index === 0
|
|
25247
|
+
})),
|
|
25248
|
+
rateLimits: null,
|
|
25249
|
+
sameAttemptRecovery: false
|
|
25250
|
+
};
|
|
25251
|
+
}
|
|
25252
|
+
async runAttempt(input) {
|
|
25253
|
+
const startedAt = (this.dependencies.now ?? Date.now)();
|
|
25254
|
+
if (Date.now() >= input.deadlineAtMs) {
|
|
25255
|
+
throw nonDispatchedError(
|
|
25256
|
+
"DeepSeek Harness attempt exceeded its deadline.",
|
|
25257
|
+
"timeout",
|
|
25258
|
+
"deadline_exceeded"
|
|
25259
|
+
);
|
|
25260
|
+
}
|
|
25261
|
+
if (!DEEPSEEK_MODELS.includes(input.requestedModel)) {
|
|
25262
|
+
throw nonDispatchedError(
|
|
25263
|
+
"The requested DeepSeek Harness model is unsupported.",
|
|
25264
|
+
"model",
|
|
25265
|
+
"deepseek_model_unsupported"
|
|
25266
|
+
);
|
|
25267
|
+
}
|
|
25268
|
+
if (!supportedEfforts(input.requestedModel).includes(input.requestedReasoningEffort)) {
|
|
25269
|
+
throw nonDispatchedError(
|
|
25270
|
+
"The requested DeepSeek Harness reasoning effort is unsupported.",
|
|
25271
|
+
"model",
|
|
25272
|
+
"deepseek_reasoning_effort_unsupported"
|
|
25273
|
+
);
|
|
25274
|
+
}
|
|
25275
|
+
const effort = effortForHarness(input.requestedReasoningEffort);
|
|
25276
|
+
const boundary = createDeadlineBoundary(input.signal, input.deadlineAtMs);
|
|
25277
|
+
let credential;
|
|
25278
|
+
try {
|
|
25279
|
+
credential = await this.dependencies.credentialStore.read(boundary.signal);
|
|
25280
|
+
if (!credential) {
|
|
25281
|
+
throw nonDispatchedError(
|
|
25282
|
+
"Import a DeepSeek API key with vtx inference-host deepseek-login first.",
|
|
25283
|
+
"auth",
|
|
25284
|
+
"deepseek_harness_credential_required"
|
|
25285
|
+
);
|
|
25286
|
+
}
|
|
25287
|
+
} catch (error48) {
|
|
25288
|
+
const cancelled = input.signal?.aborted === true;
|
|
25289
|
+
const deadline = !cancelled && boundary.signal.aborted;
|
|
25290
|
+
boundary.cleanup();
|
|
25291
|
+
if (error48 instanceof CodexAppServerError) throw error48;
|
|
25292
|
+
throw nonDispatchedError(
|
|
25293
|
+
cancelled ? "DeepSeek Harness attempt was cancelled." : deadline ? "DeepSeek Harness attempt exceeded its deadline." : "DeepSeek Harness could not read its local credential.",
|
|
25294
|
+
cancelled ? "cancelled" : deadline ? "timeout" : "auth",
|
|
25295
|
+
cancelled ? "cancelled" : deadline ? "deadline_exceeded" : "deepseek_harness_credential_read_failed"
|
|
25296
|
+
);
|
|
25297
|
+
}
|
|
25298
|
+
const proxy = new DeepSeekTransportProxy(
|
|
25299
|
+
credential.apiKey,
|
|
25300
|
+
input.requestedModel,
|
|
25301
|
+
effort,
|
|
25302
|
+
this.dependencies.apiBaseUrl ?? DEEPSEEK_API_BASE_URL,
|
|
25303
|
+
this.dependencies.fetch ?? fetch
|
|
25304
|
+
);
|
|
25305
|
+
try {
|
|
25306
|
+
boundary.signal.throwIfAborted();
|
|
25307
|
+
await proxy.start();
|
|
25308
|
+
const adapter = directAdapter(proxy, input.requestedModel, effort);
|
|
25309
|
+
const blocks = [];
|
|
25310
|
+
let usage = null;
|
|
25311
|
+
let finish = null;
|
|
25312
|
+
for await (const chunk of adapter.stream({
|
|
25313
|
+
provider: "deepseek-official",
|
|
25314
|
+
model: input.requestedModel,
|
|
25315
|
+
reasoningEffort: effort,
|
|
25316
|
+
system: `${input.systemPrompt}
|
|
25317
|
+
|
|
25318
|
+
Return only one JSON value matching this JSON Schema exactly:
|
|
25319
|
+
${input.outputSchemaJson}`,
|
|
25320
|
+
messages: [createUserMessage({
|
|
25321
|
+
content: [{ type: "text", text: input.userPrompt }],
|
|
25322
|
+
source: { kind: "user" }
|
|
25323
|
+
})],
|
|
25324
|
+
tools: [],
|
|
25325
|
+
signal: boundary.signal
|
|
25326
|
+
})) {
|
|
25327
|
+
if (chunk.type === "block-end") blocks.push(chunk.block);
|
|
25328
|
+
if (chunk.type === "usage") usage = chunk.usage;
|
|
25329
|
+
if (chunk.type === "finish") finish = chunk;
|
|
25330
|
+
}
|
|
25331
|
+
const receipts = proxy.receipts;
|
|
25332
|
+
if (receipts.length !== 1 || !usage || finish?.type !== "finish" || finish.reason.kind !== "stop") {
|
|
25333
|
+
throw new Error("deepseek_harness_terminal_receipt_invalid");
|
|
25334
|
+
}
|
|
25335
|
+
const text = validateText(textFromBlocks(blocks, "text"), "deepseek_harness_result_invalid");
|
|
25336
|
+
return {
|
|
25337
|
+
text,
|
|
25338
|
+
reasoningContent: textFromBlocks(blocks, "reasoning") || null,
|
|
25339
|
+
reasoningSummary: null,
|
|
25340
|
+
requestedModel: input.requestedModel,
|
|
25341
|
+
effectiveModel: receipts[0].model,
|
|
25342
|
+
requestedReasoningEffort: input.requestedReasoningEffort,
|
|
25343
|
+
effectiveReasoningEffort: input.requestedReasoningEffort,
|
|
25344
|
+
adapterRequestId: receipts[0].id,
|
|
25345
|
+
adapterResponseId: receipts[0].id,
|
|
25346
|
+
usage: toVtxUsage(usage),
|
|
25347
|
+
latencyMs: Math.max(0, (this.dependencies.now ?? Date.now)() - startedAt),
|
|
25348
|
+
timeToFirstTokenMs: null,
|
|
25349
|
+
terminalStatus: "completed"
|
|
25350
|
+
};
|
|
25351
|
+
} catch (error48) {
|
|
25352
|
+
const cancelled = input.signal?.aborted === true;
|
|
25353
|
+
const deadline = !cancelled && boundary.signal.aborted;
|
|
25354
|
+
throw mapDeepSeekFailure({
|
|
25355
|
+
error: error48,
|
|
25356
|
+
cancelled,
|
|
25357
|
+
deadline,
|
|
25358
|
+
dispatchOutcome: proxyDispatchOutcome(proxy)
|
|
25359
|
+
});
|
|
25360
|
+
} finally {
|
|
25361
|
+
boundary.cleanup();
|
|
25362
|
+
await proxy.close();
|
|
25363
|
+
}
|
|
25364
|
+
}
|
|
25365
|
+
async runTurn(input) {
|
|
25366
|
+
if (this.closing) {
|
|
25367
|
+
throw nonDispatchedError(
|
|
25368
|
+
"DeepSeek Harness Agent adapter is closing.",
|
|
25369
|
+
"transport",
|
|
25370
|
+
"transport_closed",
|
|
25371
|
+
true
|
|
25372
|
+
);
|
|
25373
|
+
}
|
|
25374
|
+
if (Date.now() >= input.deadlineAtMs) {
|
|
25375
|
+
throw nonDispatchedError(
|
|
25376
|
+
"DeepSeek Harness Agent turn exceeded its deadline.",
|
|
25377
|
+
"timeout",
|
|
25378
|
+
"deadline_exceeded"
|
|
25379
|
+
);
|
|
25380
|
+
}
|
|
25381
|
+
if (!DEEPSEEK_MODELS.includes(input.requestedModel)) {
|
|
25382
|
+
throw nonDispatchedError(
|
|
25383
|
+
"The requested DeepSeek Harness model is unsupported.",
|
|
25384
|
+
"model",
|
|
25385
|
+
"deepseek_model_unsupported"
|
|
25386
|
+
);
|
|
25387
|
+
}
|
|
25388
|
+
if (input.dataContract.length === 0 || !supportedEfforts(input.requestedModel).includes(input.requestedReasoningEffort)) {
|
|
25389
|
+
throw nonDispatchedError(
|
|
25390
|
+
"DeepSeek Harness Agent turn input is invalid.",
|
|
25391
|
+
"schema",
|
|
25392
|
+
"invalid_agent_turn_input"
|
|
25393
|
+
);
|
|
25394
|
+
}
|
|
25395
|
+
const startedAt = (this.dependencies.now ?? Date.now)();
|
|
25396
|
+
const effort = effortForHarness(input.requestedReasoningEffort);
|
|
25397
|
+
const boundary = createDeadlineBoundary(input.signal, input.deadlineAtMs);
|
|
25398
|
+
let credential;
|
|
25399
|
+
try {
|
|
25400
|
+
credential = await this.dependencies.credentialStore.read(boundary.signal);
|
|
25401
|
+
if (!credential) {
|
|
25402
|
+
throw nonDispatchedError(
|
|
25403
|
+
"Import a DeepSeek API key with vtx inference-host deepseek-login first.",
|
|
25404
|
+
"auth",
|
|
25405
|
+
"deepseek_harness_credential_required"
|
|
25406
|
+
);
|
|
25407
|
+
}
|
|
25408
|
+
} catch (error48) {
|
|
25409
|
+
const cancelled = input.signal?.aborted === true;
|
|
25410
|
+
const deadline = !cancelled && boundary.signal.aborted;
|
|
25411
|
+
boundary.cleanup();
|
|
25412
|
+
if (error48 instanceof CodexAppServerError) throw error48;
|
|
25413
|
+
throw nonDispatchedError(
|
|
25414
|
+
cancelled ? "DeepSeek Harness Agent turn was cancelled." : deadline ? "DeepSeek Harness Agent turn exceeded its deadline." : "DeepSeek Harness could not read its local credential.",
|
|
25415
|
+
cancelled ? "cancelled" : deadline ? "timeout" : "auth",
|
|
25416
|
+
cancelled ? "cancelled" : deadline ? "deadline_exceeded" : "deepseek_harness_credential_read_failed"
|
|
25417
|
+
);
|
|
25418
|
+
}
|
|
25419
|
+
const owned = input.durableThread ? null : await (this.dependencies.createWorkspace ?? createPrivateWorkspace2)();
|
|
25420
|
+
const rootPath = input.durableThread?.threadPath ?? owned.path;
|
|
25421
|
+
if (owned) this.agentWorkspaces.set(rootPath, owned.cleanup);
|
|
25422
|
+
const proxy = new DeepSeekTransportProxy(
|
|
25423
|
+
credential.apiKey,
|
|
25424
|
+
input.requestedModel,
|
|
25425
|
+
effort,
|
|
25426
|
+
this.dependencies.apiBaseUrl ?? DEEPSEEK_API_BASE_URL,
|
|
25427
|
+
this.dependencies.fetch ?? fetch
|
|
25428
|
+
);
|
|
25429
|
+
const ctx = new Context();
|
|
25430
|
+
const loopbackEnvName = `VTX_DSH_LOOPBACK_TOKEN_${randomUUID2().replaceAll("-", "").toUpperCase()}`;
|
|
25431
|
+
process.env[loopbackEnvName] = "vtx-loopback-only";
|
|
25432
|
+
let durableCheckpointed = input.durableThread !== null;
|
|
25433
|
+
let cleanupUnpublishedWorkspace = false;
|
|
25434
|
+
let removeAgentAbortListener = () => void 0;
|
|
25435
|
+
let cancelAgentTurn = () => void 0;
|
|
25436
|
+
let releaseAgentDispatch = () => void 0;
|
|
25437
|
+
let permitAgentDispatch = false;
|
|
25438
|
+
try {
|
|
25439
|
+
await proxy.start();
|
|
25440
|
+
await ctx.plugin(AgentSpine, {
|
|
25441
|
+
agents: [],
|
|
25442
|
+
maxParallelToolCalls: 1,
|
|
25443
|
+
includeHarnessIdentity: false,
|
|
25444
|
+
includeRuntimeContext: false,
|
|
25445
|
+
persona: `${input.systemPrompt}
|
|
25446
|
+
|
|
25447
|
+
Return only one JSON value matching this JSON Schema exactly:
|
|
25448
|
+
${JSON.stringify(input.outputSchema)}`,
|
|
25449
|
+
tools: { mode: "native" },
|
|
25450
|
+
workspaceContext: false,
|
|
25451
|
+
skills: { enabled: false },
|
|
25452
|
+
toolBash: false,
|
|
25453
|
+
toolJobs: false,
|
|
25454
|
+
goals: false
|
|
25455
|
+
});
|
|
25456
|
+
await ctx.plugin(JsonlSessionPersistence, { root: rootPath, compression: "none" });
|
|
25457
|
+
await ctx.plugin(SessionCheckpointPolicy);
|
|
25458
|
+
await ctx.plugin(LlmDeepSeek, {
|
|
25459
|
+
apiKeyEnv: loopbackEnvName,
|
|
25460
|
+
baseURL: proxy.baseUrl,
|
|
25461
|
+
reasoningEffort: effort,
|
|
25462
|
+
thinking: "enabled",
|
|
25463
|
+
models: [{ id: input.requestedModel }],
|
|
25464
|
+
retryPolicy: { mode: "normal", maxRetries: 0 }
|
|
25465
|
+
});
|
|
25466
|
+
const evidence = [];
|
|
25467
|
+
const setup = (agentCtx) => {
|
|
25468
|
+
const definitions = [
|
|
25469
|
+
{
|
|
25470
|
+
name: "vtx_get_data",
|
|
25471
|
+
description: "Request assignment-scoped VTX data.",
|
|
25472
|
+
parameters: { oneOf: input.dataContract.map((entry) => ({
|
|
25473
|
+
type: "object",
|
|
25474
|
+
additionalProperties: false,
|
|
25475
|
+
required: ["capability", "arguments"],
|
|
25476
|
+
properties: { capability: { const: entry.id }, arguments: entry.input_schema }
|
|
25477
|
+
})) }
|
|
25478
|
+
},
|
|
25479
|
+
{
|
|
25480
|
+
name: "vtx_submit_decision",
|
|
25481
|
+
description: "Submit one VTX structured trading decision candidate.",
|
|
25482
|
+
parameters: { type: "object", additionalProperties: false, required: ["candidate"], properties: { candidate: input.decisionSchema } }
|
|
25483
|
+
},
|
|
25484
|
+
{
|
|
25485
|
+
name: "vtx_decision_status",
|
|
25486
|
+
description: "Resolve the durable status of a decision operation.",
|
|
25487
|
+
parameters: { type: "object", additionalProperties: false, required: ["operation_id"], properties: { operation_id: { type: "string", minLength: 1 } } }
|
|
25488
|
+
}
|
|
25489
|
+
];
|
|
25490
|
+
for (const definition of definitions) {
|
|
25491
|
+
agentCtx.tools.register({
|
|
25492
|
+
...definition,
|
|
25493
|
+
output: {
|
|
25494
|
+
schema: {},
|
|
25495
|
+
render: (_arguments, value) => [{ type: "text", text: JSON.stringify(value) }]
|
|
25496
|
+
},
|
|
25497
|
+
execute: async (argumentsValue) => {
|
|
25498
|
+
const argumentsRecord = argumentsValue && typeof argumentsValue === "object" && !Array.isArray(argumentsValue) ? argumentsValue : {};
|
|
25499
|
+
const callId = randomUUID2();
|
|
25500
|
+
const result2 = await input.executeTool({ callId, tool: definition.name, arguments: argumentsRecord });
|
|
25501
|
+
evidence.push({ callId, tool: definition.name, arguments: argumentsRecord, success: result2.success });
|
|
25502
|
+
return normalizeJsonValue(result2.success ? result2.value : { error: result2.value });
|
|
25503
|
+
}
|
|
25504
|
+
});
|
|
25505
|
+
}
|
|
25506
|
+
};
|
|
25507
|
+
const sessionId = input.durableThread ? SessionId(input.durableThread.threadId) : SessionId(`vtx-${randomUUID2()}`);
|
|
25508
|
+
const handle = input.durableThread ? await ctx.agents.resume({
|
|
25509
|
+
resumeSessionId: sessionId,
|
|
25510
|
+
agentOptions: { provider: "deepseek-official", model: input.requestedModel, reasoningEffort: effort },
|
|
25511
|
+
signal: boundary.signal,
|
|
25512
|
+
setup
|
|
25513
|
+
}) : await ctx.agents.create({
|
|
25514
|
+
sessionId,
|
|
25515
|
+
meta: { cwd: rootPath },
|
|
25516
|
+
agentOptions: { provider: "deepseek-official", model: input.requestedModel, reasoningEffort: effort },
|
|
25517
|
+
signal: boundary.signal,
|
|
25518
|
+
setup
|
|
25519
|
+
});
|
|
25520
|
+
const onAbort = () => handle.agent.cancel({ kind: "user" });
|
|
25521
|
+
cancelAgentTurn = onAbort;
|
|
25522
|
+
boundary.signal.addEventListener("abort", onAbort, { once: true });
|
|
25523
|
+
removeAgentAbortListener = () => boundary.signal.removeEventListener("abort", onAbort);
|
|
25524
|
+
if (boundary.signal.aborted) onAbort();
|
|
25525
|
+
boundary.signal.throwIfAborted();
|
|
25526
|
+
let checkpointReached = false;
|
|
25527
|
+
let resolveCheckpoint;
|
|
25528
|
+
const checkpoint = new Promise((resolve6) => {
|
|
25529
|
+
resolveCheckpoint = resolve6;
|
|
25530
|
+
});
|
|
25531
|
+
const dispatchGate = new Promise((resolve6) => {
|
|
25532
|
+
releaseAgentDispatch = resolve6;
|
|
25533
|
+
});
|
|
25534
|
+
ctx.on("llm/stream", (options, next) => {
|
|
25535
|
+
if (String(options.sessionId ?? "") !== String(sessionId)) return next();
|
|
25536
|
+
return (async function* () {
|
|
25537
|
+
await ctx.sessions.flush(handle.agent.session);
|
|
25538
|
+
checkpointReached = true;
|
|
25539
|
+
resolveCheckpoint();
|
|
25540
|
+
await dispatchGate;
|
|
25541
|
+
boundary.signal.throwIfAborted();
|
|
25542
|
+
if (!permitAgentDispatch) throw new Error("deepseek_agent_publication_not_committed");
|
|
25543
|
+
yield* next();
|
|
25544
|
+
})();
|
|
25545
|
+
});
|
|
25546
|
+
const thread = {
|
|
25547
|
+
threadId: String(sessionId),
|
|
25548
|
+
threadPath: rootPath,
|
|
25549
|
+
effectiveModel: input.requestedModel,
|
|
25550
|
+
effectiveReasoningEffort: input.requestedReasoningEffort
|
|
25551
|
+
};
|
|
25552
|
+
const startSeq = handle.agent.session.seq;
|
|
25553
|
+
handle.agent.followup(createUserMessage({
|
|
25554
|
+
content: [{ type: "text", text: input.userPrompt }],
|
|
25555
|
+
source: { kind: "user" }
|
|
25556
|
+
}));
|
|
25557
|
+
const idle = handle.agent.whenIdle();
|
|
25558
|
+
await Promise.race([
|
|
25559
|
+
checkpoint,
|
|
25560
|
+
idle.then(() => {
|
|
25561
|
+
if (!checkpointReached) throw new Error("deepseek_agent_checkpoint_not_reached");
|
|
25562
|
+
})
|
|
25563
|
+
]);
|
|
25564
|
+
boundary.signal.throwIfAborted();
|
|
25565
|
+
if (input.onThreadReady) {
|
|
25566
|
+
await input.onThreadReady(thread);
|
|
25567
|
+
durableCheckpointed = true;
|
|
25568
|
+
}
|
|
25569
|
+
boundary.signal.throwIfAborted();
|
|
25570
|
+
permitAgentDispatch = true;
|
|
25571
|
+
releaseAgentDispatch();
|
|
25572
|
+
releaseAgentDispatch = () => void 0;
|
|
25573
|
+
await idle;
|
|
25574
|
+
const events = handle.agent.session.events.slice(startSeq);
|
|
25575
|
+
const assistantEvents = events.filter((event) => event.type === "assistant/message");
|
|
25576
|
+
const turnEnd = [...events].reverse().find((event) => event.type === "turn/end");
|
|
25577
|
+
if (!turnEnd || turnEnd.type !== "turn/end" || turnEnd.data.reason.kind !== "completed") {
|
|
25578
|
+
if (turnEnd?.type === "turn/end" && turnEnd.data.reason.kind === "error") {
|
|
25579
|
+
const failure = turnEnd.data.reason.error;
|
|
25580
|
+
throw new LlmError(failure.message, failure.code, {
|
|
25581
|
+
...failure.status === void 0 ? {} : { status: failure.status },
|
|
25582
|
+
...failure.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: failure.providerRetryAfterMs }
|
|
25583
|
+
});
|
|
25584
|
+
}
|
|
25585
|
+
const reason = turnEnd?.type === "turn/end" ? turnEnd.data.reason : { kind: "missing" };
|
|
25586
|
+
throw new Error(`deepseek_harness_agent_turn_incomplete:${JSON.stringify(reason)}`);
|
|
25587
|
+
}
|
|
25588
|
+
const last = assistantEvents.at(-1);
|
|
25589
|
+
if (!last || last.type !== "assistant/message" || last.data.interrupted) {
|
|
25590
|
+
throw new Error("deepseek_harness_agent_result_missing");
|
|
25591
|
+
}
|
|
25592
|
+
const usages = assistantEvents.flatMap((event) => event.type === "assistant/message" && event.data.usage ? [event.data.usage] : []);
|
|
25593
|
+
if (usages.length === 0 || proxy.receipts.length !== usages.length) {
|
|
25594
|
+
throw new Error("deepseek_harness_agent_receipt_missing");
|
|
25595
|
+
}
|
|
25596
|
+
const text = validateText(textFromBlocks(last.data.message.content, "text"), "deepseek_harness_agent_result_invalid");
|
|
25597
|
+
const receipts = proxy.receipts;
|
|
25598
|
+
await handle.dispose();
|
|
25599
|
+
return {
|
|
25600
|
+
thread,
|
|
25601
|
+
turn: {
|
|
25602
|
+
text,
|
|
25603
|
+
reasoningContent: textFromBlocks(last.data.message.content, "reasoning") || null,
|
|
25604
|
+
reasoningSummary: null,
|
|
25605
|
+
requestedModel: input.requestedModel,
|
|
25606
|
+
effectiveModel: receipts.at(-1).model,
|
|
25607
|
+
requestedReasoningEffort: input.requestedReasoningEffort,
|
|
25608
|
+
effectiveReasoningEffort: input.requestedReasoningEffort,
|
|
25609
|
+
adapterRequestId: receipts[0].id,
|
|
25610
|
+
adapterResponseId: receipts.at(-1).id,
|
|
25611
|
+
usage: sumUsage(usages),
|
|
25612
|
+
latencyMs: Math.max(0, (this.dependencies.now ?? Date.now)() - startedAt),
|
|
25613
|
+
timeToFirstTokenMs: null,
|
|
25614
|
+
terminalStatus: "completed",
|
|
25615
|
+
toolCalls: evidence,
|
|
25616
|
+
webSearches: []
|
|
25617
|
+
}
|
|
25618
|
+
};
|
|
25619
|
+
} catch (error48) {
|
|
25620
|
+
cancelAgentTurn();
|
|
25621
|
+
releaseAgentDispatch();
|
|
25622
|
+
releaseAgentDispatch = () => void 0;
|
|
25623
|
+
if (!durableCheckpointed && owned) {
|
|
25624
|
+
cleanupUnpublishedWorkspace = true;
|
|
25625
|
+
}
|
|
25626
|
+
throw mapDeepSeekFailure({
|
|
25627
|
+
error: error48,
|
|
25628
|
+
cancelled: input.signal?.aborted === true,
|
|
25629
|
+
deadline: input.signal?.aborted !== true && boundary.signal.aborted,
|
|
25630
|
+
dispatchOutcome: proxyDispatchOutcome(proxy)
|
|
25631
|
+
});
|
|
25632
|
+
} finally {
|
|
25633
|
+
removeAgentAbortListener();
|
|
25634
|
+
boundary.cleanup();
|
|
25635
|
+
await ctx.fiber.dispose().catch(() => void 0);
|
|
25636
|
+
await proxy.close();
|
|
25637
|
+
if (cleanupUnpublishedWorkspace && owned) {
|
|
25638
|
+
await owned.cleanup().catch(() => void 0);
|
|
25639
|
+
this.agentWorkspaces.delete(rootPath);
|
|
25640
|
+
}
|
|
25641
|
+
delete process.env[loopbackEnvName];
|
|
25642
|
+
}
|
|
25643
|
+
}
|
|
25644
|
+
async releaseThread(thread) {
|
|
25645
|
+
const cleanup = this.agentWorkspaces.get(thread.threadPath);
|
|
25646
|
+
if (cleanup) {
|
|
25647
|
+
await cleanup();
|
|
25648
|
+
this.agentWorkspaces.delete(thread.threadPath);
|
|
25649
|
+
return;
|
|
25650
|
+
}
|
|
25651
|
+
const resolved = await realpath4(thread.threadPath);
|
|
25652
|
+
const temporaryRoot = await realpath4(tmpdir4());
|
|
25653
|
+
if (dirname4(resolved) !== temporaryRoot || !basename(resolved).startsWith("vtx-deepseek-harness-")) throw new Error("deepseek_harness_thread_path_not_owned");
|
|
25654
|
+
await rm5(resolved, { recursive: true, force: true });
|
|
25655
|
+
}
|
|
25656
|
+
async close() {
|
|
25657
|
+
this.closing = true;
|
|
25658
|
+
}
|
|
25659
|
+
};
|
|
25660
|
+
}
|
|
25661
|
+
});
|
|
25662
|
+
|
|
25663
|
+
// lib/inference-host/deepseek-credential-store.ts
|
|
25664
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
25665
|
+
var DEEPSEEK_CREDENTIAL_NAMESPACE, MAX_API_KEY_BYTES, validateApiKey, credentialIdentity, parseCredential, serializeCredential, platformCommands, createDeepSeekHarnessCredentialStore;
|
|
25666
|
+
var init_deepseek_credential_store = __esm({
|
|
25667
|
+
"lib/inference-host/deepseek-credential-store.ts"() {
|
|
25668
|
+
"use strict";
|
|
25669
|
+
init_config();
|
|
25670
|
+
init_credential_store();
|
|
25671
|
+
DEEPSEEK_CREDENTIAL_NAMESPACE = "vtxmacro-deepseek-harness";
|
|
25672
|
+
MAX_API_KEY_BYTES = 512;
|
|
25673
|
+
validateApiKey = (raw) => {
|
|
25674
|
+
const apiKey = raw.trim();
|
|
25675
|
+
if (apiKey.length < 16 || Buffer.byteLength(apiKey, "utf8") > MAX_API_KEY_BYTES || /[\s\u0000-\u001f\u007f]/u.test(apiKey)) {
|
|
25676
|
+
throw new Error("DeepSeek API key is invalid. Provide one private key through stdin.");
|
|
25677
|
+
}
|
|
25678
|
+
return apiKey;
|
|
25679
|
+
};
|
|
25680
|
+
credentialIdentity = (apiKey) => `deepseek-key-${createHash5("sha256").update(apiKey).digest("hex").slice(0, 24)}`;
|
|
25681
|
+
parseCredential = (raw) => {
|
|
25682
|
+
let value;
|
|
25683
|
+
try {
|
|
25684
|
+
value = JSON.parse(raw);
|
|
25685
|
+
} catch {
|
|
25686
|
+
throw new Error("Stored DeepSeek Harness credential is invalid JSON.");
|
|
25687
|
+
}
|
|
25688
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
25689
|
+
throw new Error("Stored DeepSeek Harness credential is invalid.");
|
|
25690
|
+
}
|
|
25691
|
+
const record2 = value;
|
|
25692
|
+
const apiKey = validateApiKey(String(record2.api_key ?? ""));
|
|
25693
|
+
const identity = credentialIdentity(apiKey);
|
|
25694
|
+
if (record2.schema_version !== 1 || record2.adapter !== "deepseek-harness" || record2.identity !== identity || Object.keys(record2).sort().join(",") !== "adapter,api_key,identity,schema_version") {
|
|
25695
|
+
throw new Error("Stored DeepSeek Harness credential failed validation.");
|
|
25696
|
+
}
|
|
25697
|
+
return { apiKey, identity };
|
|
25698
|
+
};
|
|
25699
|
+
serializeCredential = (apiKey) => {
|
|
25700
|
+
const validated = validateApiKey(apiKey);
|
|
25701
|
+
return `${JSON.stringify({
|
|
25702
|
+
schema_version: 1,
|
|
25703
|
+
adapter: "deepseek-harness",
|
|
25704
|
+
api_key: validated,
|
|
25705
|
+
identity: credentialIdentity(validated)
|
|
25706
|
+
})}
|
|
25707
|
+
`;
|
|
25708
|
+
};
|
|
25709
|
+
platformCommands = (env, platform) => {
|
|
25710
|
+
if (platform === "win32") return windowsInferenceCredentialCommands;
|
|
25711
|
+
if (platform === "linux" && String(env.WSL_INTEROP || "").trim()) {
|
|
25712
|
+
return windowsInferenceCredentialCommands;
|
|
25713
|
+
}
|
|
25714
|
+
if (platform === "linux") return linuxSecretServiceInferenceCredentialCommands;
|
|
25715
|
+
if (platform === "darwin") return macosKeychainInferenceCredentialCommands;
|
|
25716
|
+
return null;
|
|
25717
|
+
};
|
|
25718
|
+
createDeepSeekHarnessCredentialStore = (config2, dependencies = {}) => {
|
|
25719
|
+
const accountKey = `deepseek-harness:${config2.instanceName}`;
|
|
25720
|
+
const path = `${config2.statePath}.deepseek-harness-secret.json`;
|
|
25721
|
+
const env = dependencies.env ?? process.env;
|
|
25722
|
+
const platform = dependencies.platform ?? process.platform;
|
|
25723
|
+
const commands = dependencies.commands === void 0 ? platformCommands(env, platform) : dependencies.commands;
|
|
25724
|
+
const runner = dependencies.commandRunner ?? runCredentialCommand;
|
|
25725
|
+
if (config2.credentialStoreMode === "os") {
|
|
25726
|
+
if (!commands) {
|
|
25727
|
+
throw new Error("OS credential storage is unavailable for the DeepSeek API key.");
|
|
25728
|
+
}
|
|
25729
|
+
return {
|
|
25730
|
+
read: async (signal) => {
|
|
25731
|
+
const command = commands.lookup(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25732
|
+
const result2 = await runner(command, { stdin: null, signal });
|
|
25733
|
+
if ((command.notFoundExitCodes ?? []).includes(result2.exitCode)) return null;
|
|
25734
|
+
if (result2.exitCode !== 0) throw new Error("DeepSeek OS credential lookup failed.");
|
|
25735
|
+
return parseCredential(result2.stdout);
|
|
25736
|
+
},
|
|
25737
|
+
write: async (apiKey, signal) => {
|
|
25738
|
+
const serialized = serializeCredential(apiKey);
|
|
25739
|
+
const priorLookup = commands.lookup(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25740
|
+
const priorResult = await runner(priorLookup, { stdin: null, signal });
|
|
25741
|
+
const prior = (priorLookup.notFoundExitCodes ?? []).includes(priorResult.exitCode) ? null : priorResult.exitCode === 0 ? parseCredential(priorResult.stdout) : void 0;
|
|
25742
|
+
if (prior === void 0) throw new Error("DeepSeek OS credential lookup failed before write.");
|
|
25743
|
+
const command = commands.store(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25744
|
+
if (command.args.some((value) => value.includes(validateApiKey(apiKey)))) {
|
|
25745
|
+
throw new Error("DeepSeek API key must never be passed in command arguments.");
|
|
25746
|
+
}
|
|
25747
|
+
try {
|
|
25748
|
+
const result2 = await runner(command, { stdin: serialized, signal });
|
|
25749
|
+
if (result2.exitCode !== 0) throw new Error("DeepSeek OS credential write failed.");
|
|
25750
|
+
const retainedCommand = commands.lookup(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25751
|
+
const retained = await runner(retainedCommand, { stdin: null, signal });
|
|
25752
|
+
if (retained.exitCode !== 0) {
|
|
25753
|
+
throw new Error("DeepSeek OS credential write could not be verified.");
|
|
25754
|
+
}
|
|
25755
|
+
const expected = parseCredential(serialized);
|
|
25756
|
+
const observed = parseCredential(retained.stdout);
|
|
25757
|
+
if (observed.identity !== expected.identity || observed.apiKey !== expected.apiKey) {
|
|
25758
|
+
throw new Error("DeepSeek OS credential write could not be verified.");
|
|
25759
|
+
}
|
|
25760
|
+
return observed;
|
|
25761
|
+
} catch (error48) {
|
|
25762
|
+
const rollback = prior ? commands.store(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey) : commands.remove(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25763
|
+
const rollbackResult = await runner(rollback, {
|
|
25764
|
+
stdin: prior ? serializeCredential(prior.apiKey) : null
|
|
25765
|
+
});
|
|
25766
|
+
if (rollbackResult.exitCode !== 0 && !(rollback.notFoundExitCodes ?? []).includes(rollbackResult.exitCode)) {
|
|
25767
|
+
throw new Error("DeepSeek OS credential write failed and rollback failed.", {
|
|
25768
|
+
cause: error48
|
|
25769
|
+
});
|
|
25770
|
+
}
|
|
25771
|
+
const verifyCommand = commands.lookup(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25772
|
+
const verified = await runner(verifyCommand, { stdin: null });
|
|
25773
|
+
const absent = (verifyCommand.notFoundExitCodes ?? []).includes(verified.exitCode);
|
|
25774
|
+
const restored = prior && verified.exitCode === 0 ? parseCredential(verified.stdout) : null;
|
|
25775
|
+
if (prior === null && !absent || prior !== null && (!restored || restored.identity !== prior.identity || restored.apiKey !== prior.apiKey)) {
|
|
25776
|
+
throw new Error("DeepSeek OS credential write failed and rollback could not be verified.", {
|
|
25777
|
+
cause: error48
|
|
25778
|
+
});
|
|
25779
|
+
}
|
|
25780
|
+
throw error48;
|
|
25781
|
+
}
|
|
25782
|
+
},
|
|
25783
|
+
remove: async (signal) => {
|
|
25784
|
+
const command = commands.remove(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25785
|
+
const result2 = await runner(command, { stdin: null, signal });
|
|
25786
|
+
if (result2.exitCode !== 0 && !(command.notFoundExitCodes ?? []).includes(result2.exitCode)) throw new Error("DeepSeek OS credential removal failed.");
|
|
25787
|
+
const retainedCommand = commands.lookup(DEEPSEEK_CREDENTIAL_NAMESPACE, accountKey);
|
|
25788
|
+
const retained = await runner(retainedCommand, { stdin: null });
|
|
25789
|
+
if (!(retainedCommand.notFoundExitCodes ?? []).includes(retained.exitCode)) {
|
|
25790
|
+
throw new Error("DeepSeek OS credential removal could not be verified.");
|
|
25791
|
+
}
|
|
25792
|
+
}
|
|
25793
|
+
};
|
|
25794
|
+
}
|
|
25795
|
+
return {
|
|
25796
|
+
read: async () => {
|
|
25797
|
+
const raw = await readInferencePrivateFile(path, "DeepSeek Harness credential file");
|
|
25798
|
+
return raw === null ? null : parseCredential(raw);
|
|
25799
|
+
},
|
|
25800
|
+
write: async (apiKey) => {
|
|
25801
|
+
const serialized = serializeCredential(apiKey);
|
|
25802
|
+
await writeAtomicInferencePrivateFile(path, serialized);
|
|
25803
|
+
const retained = await readInferencePrivateFile(path, "DeepSeek Harness credential file");
|
|
25804
|
+
if (retained !== serialized) throw new Error("DeepSeek credential write could not be verified.");
|
|
25805
|
+
return parseCredential(serialized);
|
|
25806
|
+
},
|
|
25807
|
+
remove: async () => {
|
|
25808
|
+
await clearInferencePrivateFile(path, "DeepSeek Harness credential file");
|
|
25809
|
+
}
|
|
25810
|
+
};
|
|
24340
25811
|
};
|
|
24341
25812
|
}
|
|
24342
25813
|
});
|
|
@@ -24348,12 +25819,14 @@ var init_durable_adapter = __esm({
|
|
|
24348
25819
|
"use strict";
|
|
24349
25820
|
DURABLE_INFERENCE_ADAPTER_IDS = [
|
|
24350
25821
|
"codex",
|
|
24351
|
-
"copilot"
|
|
25822
|
+
"copilot",
|
|
25823
|
+
"deepseek-harness"
|
|
24352
25824
|
];
|
|
24353
25825
|
isDurableInferenceAdapterId = (value) => DURABLE_INFERENCE_ADAPTER_IDS.includes(value);
|
|
24354
25826
|
durableAdapterDisplayName = (adapter) => ({
|
|
24355
25827
|
codex: "Codex",
|
|
24356
|
-
copilot: "GitHub Copilot"
|
|
25828
|
+
copilot: "GitHub Copilot",
|
|
25829
|
+
"deepseek-harness": "DeepSeek Harness"
|
|
24357
25830
|
})[adapter];
|
|
24358
25831
|
}
|
|
24359
25832
|
});
|
|
@@ -24362,13 +25835,13 @@ var init_durable_adapter = __esm({
|
|
|
24362
25835
|
import {
|
|
24363
25836
|
createCipheriv,
|
|
24364
25837
|
createDecipheriv,
|
|
24365
|
-
createHash as
|
|
25838
|
+
createHash as createHash6,
|
|
24366
25839
|
createPrivateKey,
|
|
24367
25840
|
createPublicKey,
|
|
24368
25841
|
diffieHellman,
|
|
24369
25842
|
generateKeyPairSync,
|
|
24370
25843
|
hkdfSync,
|
|
24371
|
-
randomBytes as
|
|
25844
|
+
randomBytes as randomBytes5
|
|
24372
25845
|
} from "node:crypto";
|
|
24373
25846
|
var ENVELOPE_SUITE, JOB_KEY_PAYLOAD_SCHEMA_VERSION, WRAP_HKDF_INFO, PAYLOAD_HKDF_INFO, X25519_PKCS8_PREFIX, X25519_SPKI_PREFIX, ExternalInferenceEnvelopeError, canonicalize, canonicalEnvelopeAadBytes, externalInferenceSha256, decodeCanonicalBase64Url, rawPrivateKey, rawPublicKey, rawPublicBytes, aesGcmDecrypt, aesGcmEncrypt, assertIdentity, validatePlaintext, generateExternalInferenceEnvelopeKeyPair, externalInferenceEnvelopePublicKey, deriveKey, deriveExternalInferencePayloadKey, unwrapExternalInferenceJobKey, decryptExternalInferenceJobInput, decryptExternalInferenceClaim, sealExternalInferenceCandidate;
|
|
24374
25847
|
var init_crypto = __esm({
|
|
@@ -24401,7 +25874,7 @@ var init_crypto = __esm({
|
|
|
24401
25874
|
const aad = envelopeAadSchema.parse(input);
|
|
24402
25875
|
return Buffer.from(JSON.stringify(canonicalize(aad)), "utf8");
|
|
24403
25876
|
};
|
|
24404
|
-
externalInferenceSha256 = (value) =>
|
|
25877
|
+
externalInferenceSha256 = (value) => createHash6("sha256").update(value).digest("hex");
|
|
24405
25878
|
decodeCanonicalBase64Url = (value, fieldName, expectedBytes) => {
|
|
24406
25879
|
if (!/^[A-Za-z0-9_-]+$/u.test(value)) {
|
|
24407
25880
|
throw new ExternalInferenceEnvelopeError("invalid_encoding", `${fieldName} is invalid.`);
|
|
@@ -24500,7 +25973,7 @@ var init_crypto = __esm({
|
|
|
24500
25973
|
return Buffer.from(hkdfSync(
|
|
24501
25974
|
"sha256",
|
|
24502
25975
|
root,
|
|
24503
|
-
|
|
25976
|
+
createHash6("sha256").update(aadBytes).digest(),
|
|
24504
25977
|
info,
|
|
24505
25978
|
32
|
|
24506
25979
|
));
|
|
@@ -24642,7 +26115,7 @@ var init_crypto = __esm({
|
|
|
24642
26115
|
"External inference candidate must not be empty."
|
|
24643
26116
|
);
|
|
24644
26117
|
}
|
|
24645
|
-
const nonce = options.nonce ? Buffer.from(options.nonce) :
|
|
26118
|
+
const nonce = options.nonce ? Buffer.from(options.nonce) : randomBytes5(12);
|
|
24646
26119
|
if (nonce.length !== 12) {
|
|
24647
26120
|
throw new ExternalInferenceEnvelopeError(
|
|
24648
26121
|
"invalid_nonce",
|
|
@@ -30914,7 +32387,7 @@ var require_ajv = __commonJS({
|
|
|
30914
32387
|
});
|
|
30915
32388
|
|
|
30916
32389
|
// lib/inference-host/runner.ts
|
|
30917
|
-
import { createHash as
|
|
32390
|
+
import { createHash as createHash7, randomUUID as randomUUID3 } from "node:crypto";
|
|
30918
32391
|
function createDefaultInferenceHostRunnerDependencies(options) {
|
|
30919
32392
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
30920
32393
|
return {
|
|
@@ -30949,7 +32422,7 @@ function createDefaultInferenceHostRunnerDependencies(options) {
|
|
|
30949
32422
|
envelopePublicKey: options.envelopePublicKey
|
|
30950
32423
|
};
|
|
30951
32424
|
}
|
|
30952
|
-
var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_PROVIDER_RATE_LIMIT_REFRESH_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, MIN_SLEEP_MS, MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS, HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, MAX_ATTEMPT_START_RETRY_DELAY_MS, UNBOUNDED_AVAILABLE_SLOTS, buildInferenceAdvertisedModels, summarizeInferenceHostRuntimeRecovery, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, settlesWithin, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, providerWeeklyQuotaFromRateLimits, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, membershipFailureDisposition, safeFailureCode, attemptStartRetryFallbackMs, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner,
|
|
32425
|
+
var import_ajv, RUNTIME_RECEIPT_SCHEMA_VERSION, ATTEMPT_RECEIPT_SCHEMA_VERSION, DEFAULT_ADVERTISEMENT_TTL_MS, DEFAULT_ADVERTISEMENT_REFRESH_LEAD_MS, DEFAULT_HOST_HEARTBEAT_MS, DEFAULT_PROVIDER_RATE_LIMIT_REFRESH_MS, DEFAULT_ATTEMPT_HEARTBEAT_MS, DEFAULT_DRAIN_TIMEOUT_MS, DEFAULT_REMOTE_RETRY_LIMIT, MIN_SLEEP_MS, MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS, HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR, DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS, DEFAULT_AGENT_RATE_LIMIT_COOLDOWN_MS, DEFAULT_AGENT_QUOTA_COOLDOWN_MS, DEFAULT_AGENT_TRANSIENT_COOLDOWN_MS, MIN_CLAIM_START_WINDOW_MS, MAX_ATTEMPT_START_RETRY_DELAY_MS, UNBOUNDED_AVAILABLE_SLOTS, buildInferenceAdvertisedModels, summarizeInferenceHostRuntimeRecovery, FileInferenceHostRuntimeReceiptStore, InferenceHostRecoveryRequiredError, InferenceHostRunnerError, defaultSleep, abortError, settlesWithin, defaultRegisterSignalHandlers, safeInteger, exactObjectKeys, validIso, validateAttemptReceipt, validateRuntimeReceipt, sha256, stableOperationId, buildAttemptStartRequest, isoAt, providerWeeklyQuotaFromRateLimits, finitePositiveOption, validateRunnerOptions, assertLocalCredentialIdentity, retryableRemoteError, remoteRetryAfterMs, controlPlaneFatal, defaultValidateOutput, objectRecord, positiveUtf8ByteLimit, assertCompilableOutputSchema, parseOutputContract, membershipFailureDisposition, safeFailureCode, attemptStartRetryFallbackMs, exactJson2, runnerIdentityMismatch, assertAdvertisementResult, assertHostHeartbeatResult, assertClaimResult, assertStartResult, assertJobHeartbeatResult, assertTerminalResult, classifyFailure, ambiguousHeartbeatTransport, reportedTokenUsage, reportedUsage, InferenceHostRunner, createInferenceAgentControlClient, INFERENCE_AGENT_SYSTEM_PROMPT, INFERENCE_AGENT_WAKE_SCHEMA, parseInferenceAgentWake, InferenceAgentRuntime;
|
|
30953
32426
|
var init_runner = __esm({
|
|
30954
32427
|
"lib/inference-host/runner.ts"() {
|
|
30955
32428
|
"use strict";
|
|
@@ -30975,6 +32448,9 @@ var init_runner = __esm({
|
|
|
30975
32448
|
MIN_HOST_HEARTBEAT_GAP_DIAGNOSTIC_MS = 1e4;
|
|
30976
32449
|
HOST_HEARTBEAT_GAP_DIAGNOSTIC_FACTOR = 3;
|
|
30977
32450
|
DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
32451
|
+
DEFAULT_AGENT_RATE_LIMIT_COOLDOWN_MS = 6e4;
|
|
32452
|
+
DEFAULT_AGENT_QUOTA_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
32453
|
+
DEFAULT_AGENT_TRANSIENT_COOLDOWN_MS = 5e3;
|
|
30978
32454
|
MIN_CLAIM_START_WINDOW_MS = 5e3;
|
|
30979
32455
|
MAX_ATTEMPT_START_RETRY_DELAY_MS = 15e3;
|
|
30980
32456
|
UNBOUNDED_AVAILABLE_SLOTS = Number.MAX_SAFE_INTEGER;
|
|
@@ -31241,7 +32717,7 @@ var init_runner = __esm({
|
|
|
31241
32717
|
attempts
|
|
31242
32718
|
};
|
|
31243
32719
|
};
|
|
31244
|
-
sha256 = (value) =>
|
|
32720
|
+
sha256 = (value) => createHash7("sha256").update(value, "utf8").digest("hex");
|
|
31245
32721
|
stableOperationId = (kind, parts) => `${kind}_${sha256(JSON.stringify(parts)).slice(0, 48)}`;
|
|
31246
32722
|
buildAttemptStartRequest = (claim, attemptId, startedAt) => attemptStartRequestSchema.parse({
|
|
31247
32723
|
schema_version: "external_inference_attempt_start_v1",
|
|
@@ -31333,7 +32809,7 @@ var init_runner = __esm({
|
|
|
31333
32809
|
adapterId,
|
|
31334
32810
|
options.structuredOutput ?? adapterId === "codex",
|
|
31335
32811
|
options.sameAttemptRecovery ?? adapterId === "codex",
|
|
31336
|
-
options.agentRuntime
|
|
32812
|
+
options.agentRuntime ? ["provider", "agent"] : ["provider"]
|
|
31337
32813
|
),
|
|
31338
32814
|
maxConcurrency: options.maxConcurrency === null || options.maxConcurrency === void 0 ? null : finitePositiveOption(options.maxConcurrency, 1, "Maximum concurrency"),
|
|
31339
32815
|
advertisementTtlMs,
|
|
@@ -31514,7 +32990,7 @@ var init_runner = __esm({
|
|
|
31514
32990
|
membershipFailureDisposition = (failure) => {
|
|
31515
32991
|
if (failure.dispatchOutcome === "outcome_unknown") return "quarantine_ambiguous";
|
|
31516
32992
|
if (failure.category === "auth" || ["auth_expired", "managed_chatgpt_auth_required", "invalid_account_metadata"].includes(failure.code)) return "cascade_disable";
|
|
31517
|
-
if (failure.category === "quota" || ["quota_exceeded", "codex_rate_limited"].includes(failure.code)) return "cascade_cooldown";
|
|
32993
|
+
if (failure.category === "quota" || ["quota_exceeded", "codex_rate_limited", "provider_rate_limited"].includes(failure.code)) return "cascade_cooldown";
|
|
31518
32994
|
if (failure.retryable && (["adapter", "network", "transport"].includes(failure.category) || failure.code === "rpc_timeout")) return "retry_same_host";
|
|
31519
32995
|
if (["model_unavailable", "reasoning_effort_unavailable"].includes(failure.code)) return "cascade_cooldown";
|
|
31520
32996
|
if ([
|
|
@@ -31788,10 +33264,48 @@ var init_runner = __esm({
|
|
|
31788
33264
|
const agentRuntimeSettings = settings.agentRuntime;
|
|
31789
33265
|
agentLoop = (async () => {
|
|
31790
33266
|
while (!agentAbort.signal.aborted) {
|
|
31791
|
-
const
|
|
33267
|
+
const existingFence = await readInferenceAgentFailureFence(
|
|
33268
|
+
agentRuntimeSettings.statePath
|
|
33269
|
+
);
|
|
33270
|
+
if (existingFence) {
|
|
33271
|
+
if (existingFence.adapter_id !== settings.adapterId || existingFence.host_id !== localState.host_id) {
|
|
33272
|
+
throw new InferenceHostRecoveryRequiredError(
|
|
33273
|
+
"Inference Agent failure fence belongs to another host or adapter."
|
|
33274
|
+
);
|
|
33275
|
+
}
|
|
33276
|
+
if (existingFence.retry_at === null) {
|
|
33277
|
+
emitDiagnostic("agent_runtime_quarantined", {
|
|
33278
|
+
assignment_id: existingFence.assignment_id,
|
|
33279
|
+
failure_category: existingFence.failure_category,
|
|
33280
|
+
failure_code: existingFence.failure_code,
|
|
33281
|
+
dispatch_outcome: existingFence.dispatch_outcome
|
|
33282
|
+
});
|
|
33283
|
+
return;
|
|
33284
|
+
}
|
|
33285
|
+
const retryAtMs = Date.parse(existingFence.retry_at);
|
|
33286
|
+
if (retryAtMs > now()) {
|
|
33287
|
+
emitDiagnostic("agent_runtime_cooldown", {
|
|
33288
|
+
assignment_id: existingFence.assignment_id,
|
|
33289
|
+
failure_category: existingFence.failure_category,
|
|
33290
|
+
failure_code: existingFence.failure_code,
|
|
33291
|
+
dispatch_outcome: existingFence.dispatch_outcome,
|
|
33292
|
+
cooldown_until: existingFence.retry_at
|
|
33293
|
+
});
|
|
33294
|
+
if (this.options.once) return;
|
|
33295
|
+
try {
|
|
33296
|
+
await sleep4(Math.max(MIN_SLEEP_MS, retryAtMs - now()), agentAbort.signal);
|
|
33297
|
+
} catch {
|
|
33298
|
+
return;
|
|
33299
|
+
}
|
|
33300
|
+
continue;
|
|
33301
|
+
}
|
|
33302
|
+
await clearInferenceAgentFailureFence(agentRuntimeSettings.statePath);
|
|
33303
|
+
}
|
|
33304
|
+
const agentRuntime = new InferenceAgentRuntime({
|
|
33305
|
+
adapterId: settings.adapterId,
|
|
31792
33306
|
hostId: localState.host_id,
|
|
31793
33307
|
statePath: agentRuntimeSettings.statePath,
|
|
31794
|
-
controlClient:
|
|
33308
|
+
controlClient: createInferenceAgentControlClient(mcp),
|
|
31795
33309
|
adapter: agentRuntimeSettings.adapter
|
|
31796
33310
|
});
|
|
31797
33311
|
try {
|
|
@@ -31807,6 +33321,51 @@ var init_runner = __esm({
|
|
|
31807
33321
|
requestDrain("authority_lost");
|
|
31808
33322
|
return;
|
|
31809
33323
|
}
|
|
33324
|
+
if (error48 instanceof CodexAppServerError) {
|
|
33325
|
+
const failure = classifyFailure(error48);
|
|
33326
|
+
const providerLimited = failure.category === "auth" || failure.category === "quota" || ["quota_exceeded", "codex_rate_limited", "provider_rate_limited"].includes(failure.code);
|
|
33327
|
+
const deepSeekTransient = settings.adapterId === "deepseek-harness" && failure.retryable;
|
|
33328
|
+
if (failure.dispatchOutcome === "outcome_unknown" || providerLimited || deepSeekTransient) {
|
|
33329
|
+
const runtimeState = await readInferenceAgentRuntimeState(
|
|
33330
|
+
agentRuntimeSettings.statePath
|
|
33331
|
+
);
|
|
33332
|
+
const retryAtMs = failure.dispatchOutcome === "outcome_unknown" || failure.category === "auth" && settings.adapterId === "deepseek-harness" ? null : error48.retryAtMs !== null && error48.retryAtMs > now() ? error48.retryAtMs : now() + (failure.category === "quota" || failure.code === "quota_exceeded" ? DEFAULT_AGENT_QUOTA_COOLDOWN_MS : failure.category === "auth" ? DEFAULT_CODEX_ACCOUNT_COOLDOWN_MS : failure.code === "provider_rate_limited" || failure.code === "codex_rate_limited" ? DEFAULT_AGENT_RATE_LIMIT_COOLDOWN_MS : DEFAULT_AGENT_TRANSIENT_COOLDOWN_MS);
|
|
33333
|
+
await writeInferenceAgentFailureFence(agentRuntimeSettings.statePath, {
|
|
33334
|
+
schema_version: "vtx_inference_agent_failure_fence_v1",
|
|
33335
|
+
adapter_id: settings.adapterId,
|
|
33336
|
+
host_id: localState.host_id,
|
|
33337
|
+
assignment_id: runtimeState?.schema_version === "vtx_inference_agent_runtime_v3" ? runtimeState.assignment.assignment_id : null,
|
|
33338
|
+
failure_category: safeFailureCode(failure.category, "adapter"),
|
|
33339
|
+
failure_code: safeFailureCode(failure.code, "adapter_failure"),
|
|
33340
|
+
dispatch_outcome: failure.dispatchOutcome,
|
|
33341
|
+
retry_at: retryAtMs === null ? null : isoAt(retryAtMs),
|
|
33342
|
+
created_at: isoAt(now())
|
|
33343
|
+
});
|
|
33344
|
+
if (failure.dispatchOutcome !== "outcome_unknown") {
|
|
33345
|
+
try {
|
|
33346
|
+
await agentRuntime.releaseAfterProviderFailure(failure.code);
|
|
33347
|
+
} catch {
|
|
33348
|
+
}
|
|
33349
|
+
}
|
|
33350
|
+
emitDiagnostic(
|
|
33351
|
+
retryAtMs === null ? "agent_runtime_quarantined" : "agent_runtime_cooldown",
|
|
33352
|
+
{
|
|
33353
|
+
assignment_id: runtimeState?.schema_version === "vtx_inference_agent_runtime_v3" ? runtimeState.assignment.assignment_id : null,
|
|
33354
|
+
failure_category: failure.category,
|
|
33355
|
+
failure_code: failure.code,
|
|
33356
|
+
dispatch_outcome: failure.dispatchOutcome,
|
|
33357
|
+
cooldown_until: retryAtMs === null ? null : isoAt(retryAtMs)
|
|
33358
|
+
}
|
|
33359
|
+
);
|
|
33360
|
+
if (this.options.once || retryAtMs === null) return;
|
|
33361
|
+
try {
|
|
33362
|
+
await sleep4(Math.max(MIN_SLEEP_MS, retryAtMs - now()), agentAbort.signal);
|
|
33363
|
+
} catch {
|
|
33364
|
+
return;
|
|
33365
|
+
}
|
|
33366
|
+
continue;
|
|
33367
|
+
}
|
|
33368
|
+
}
|
|
31810
33369
|
emitDiagnostic("agent_runtime_retry", {
|
|
31811
33370
|
error_code: error48 && typeof error48 === "object" && "code" in error48 ? String(error48.code) : "agent_runtime_error"
|
|
31812
33371
|
});
|
|
@@ -31819,7 +33378,13 @@ var init_runner = __esm({
|
|
|
31819
33378
|
}
|
|
31820
33379
|
}
|
|
31821
33380
|
})();
|
|
31822
|
-
void agentLoop.catch(() =>
|
|
33381
|
+
void agentLoop.catch((error48) => {
|
|
33382
|
+
if (agentAbort.signal.aborted) return;
|
|
33383
|
+
emitDiagnostic("agent_runtime_fence_failed", {
|
|
33384
|
+
error_code: error48 && typeof error48 === "object" && "code" in error48 ? String(error48.code) : "agent_runtime_fence_failed"
|
|
33385
|
+
});
|
|
33386
|
+
requestDrain("agent_recovery_failed");
|
|
33387
|
+
});
|
|
31823
33388
|
}
|
|
31824
33389
|
const existingReceipt = await this.dependencies.receiptStore.read();
|
|
31825
33390
|
const identityMatches = existingReceipt && existingReceipt.host_id === localState.host_id && existingReceipt.host_generation === localState.host_generation && existingReceipt.key_generation === localState.key_generation;
|
|
@@ -32997,10 +34562,10 @@ var init_runner = __esm({
|
|
|
32997
34562
|
if (error48 instanceof InferenceHostRunnerError && error48.code === "terminal_outcome_unconfirmed") {
|
|
32998
34563
|
throw error48;
|
|
32999
34564
|
}
|
|
33000
|
-
if (error48 instanceof CodexAppServerError && error48.retryAtMs !== null && ["quota_exceeded", "codex_rate_limited"].includes(error48.code)) {
|
|
34565
|
+
if (error48 instanceof CodexAppServerError && error48.retryAtMs !== null && ["quota_exceeded", "codex_rate_limited", "provider_rate_limited"].includes(error48.code)) {
|
|
33001
34566
|
options.onProviderCooldown?.({
|
|
33002
34567
|
retryAtMs: error48.retryAtMs,
|
|
33003
|
-
reason: error48.code === "quota_exceeded" ? "quota_exceeded" : "codex_rate_limited",
|
|
34568
|
+
reason: error48.code === "quota_exceeded" ? "quota_exceeded" : error48.code === "provider_rate_limited" ? "provider_rate_limited" : "codex_rate_limited",
|
|
33004
34569
|
rateLimits: error48.rateLimits
|
|
33005
34570
|
});
|
|
33006
34571
|
}
|
|
@@ -33129,7 +34694,7 @@ var init_runner = __esm({
|
|
|
33129
34694
|
}
|
|
33130
34695
|
}
|
|
33131
34696
|
};
|
|
33132
|
-
|
|
34697
|
+
createInferenceAgentControlClient = (mcp) => ({
|
|
33133
34698
|
nextAssignment: async (request, options) => {
|
|
33134
34699
|
const result2 = await mcp.callTool("inference.agent.assignment.next", {
|
|
33135
34700
|
...request,
|
|
@@ -33172,9 +34737,9 @@ var init_runner = __esm({
|
|
|
33172
34737
|
await mcp.callTool("inference.agent.assignment.release", request, options);
|
|
33173
34738
|
}
|
|
33174
34739
|
});
|
|
33175
|
-
|
|
34740
|
+
INFERENCE_AGENT_SYSTEM_PROMPT = `You autonomously control one running VTX bot.
|
|
33176
34741
|
VTX supplies no trading prompt or prepared market context. At your own cadence, request zero, some, or all assignment-scoped data with vtx_get_data and independently use web search when useful. Submit trading instructions only through vtx_submit_decision, using the assignment's exact decision schema. VTX remains responsible for validating and executing the same structured decision used by normal Server and Client modes. You have no shell, filesystem-write, app, plugin, browser-control, or subagent authority.`;
|
|
33177
|
-
|
|
34742
|
+
INFERENCE_AGENT_WAKE_SCHEMA = {
|
|
33178
34743
|
type: "object",
|
|
33179
34744
|
additionalProperties: false,
|
|
33180
34745
|
required: ["next_wake_seconds", "summary"],
|
|
@@ -33183,29 +34748,29 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33183
34748
|
summary: { type: "string", minLength: 1, maxLength: 2e3 }
|
|
33184
34749
|
}
|
|
33185
34750
|
};
|
|
33186
|
-
|
|
34751
|
+
parseInferenceAgentWake = (text, assignment) => {
|
|
33187
34752
|
let value;
|
|
33188
34753
|
try {
|
|
33189
34754
|
value = JSON.parse(text);
|
|
33190
34755
|
} catch {
|
|
33191
34756
|
throw new InferenceHostRunnerError(
|
|
33192
34757
|
"invalid_agent_wake",
|
|
33193
|
-
"
|
|
34758
|
+
"Inference Agent returned invalid wake JSON."
|
|
33194
34759
|
);
|
|
33195
34760
|
}
|
|
33196
34761
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
33197
|
-
throw new InferenceHostRunnerError("invalid_agent_wake", "
|
|
34762
|
+
throw new InferenceHostRunnerError("invalid_agent_wake", "Inference Agent wake is invalid.");
|
|
33198
34763
|
}
|
|
33199
34764
|
const seconds = value.next_wake_seconds;
|
|
33200
34765
|
if (!Number.isSafeInteger(seconds) || Number(seconds) < 1) {
|
|
33201
|
-
throw new InferenceHostRunnerError("invalid_agent_wake", "
|
|
34766
|
+
throw new InferenceHostRunnerError("invalid_agent_wake", "Inference Agent wake is invalid.");
|
|
33202
34767
|
}
|
|
33203
34768
|
return Math.max(
|
|
33204
34769
|
assignment.minimum_wake_seconds,
|
|
33205
34770
|
Math.min(assignment.maximum_wake_seconds, Number(seconds))
|
|
33206
34771
|
);
|
|
33207
34772
|
};
|
|
33208
|
-
|
|
34773
|
+
InferenceAgentRuntime = class {
|
|
33209
34774
|
constructor(options) {
|
|
33210
34775
|
this.options = options;
|
|
33211
34776
|
this.stopped = false;
|
|
@@ -33215,6 +34780,9 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33215
34780
|
stop() {
|
|
33216
34781
|
this.stopped = true;
|
|
33217
34782
|
}
|
|
34783
|
+
async releaseAfterProviderFailure(reasonCode) {
|
|
34784
|
+
await this.releaseForHostStop(safeFailureCode(reasonCode, "provider_failure"));
|
|
34785
|
+
}
|
|
33218
34786
|
async run(signal) {
|
|
33219
34787
|
let exitedNormally = false;
|
|
33220
34788
|
try {
|
|
@@ -33231,37 +34799,67 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33231
34799
|
}
|
|
33232
34800
|
}
|
|
33233
34801
|
async runSingle(signal) {
|
|
34802
|
+
let exitedNormally = false;
|
|
33234
34803
|
try {
|
|
33235
34804
|
await this.runOnce(signal);
|
|
34805
|
+
exitedNormally = true;
|
|
33236
34806
|
} finally {
|
|
33237
|
-
|
|
34807
|
+
if (exitedNormally || this.stopped || signal?.aborted) {
|
|
34808
|
+
await this.releaseForHostStop();
|
|
34809
|
+
}
|
|
33238
34810
|
}
|
|
33239
34811
|
}
|
|
33240
34812
|
async runOnce(signal) {
|
|
33241
34813
|
const nowIso = () => new Date(this.now()).toISOString();
|
|
33242
|
-
const recoveredState = await
|
|
34814
|
+
const recoveredState = await readInferenceAgentRuntimeState(this.options.statePath);
|
|
33243
34815
|
if (recoveredState && recoveredState.host_id !== this.options.hostId) {
|
|
33244
34816
|
throw new InferenceHostRunnerError(
|
|
33245
34817
|
"agent_recovery_scope_mismatch",
|
|
33246
|
-
"
|
|
34818
|
+
"Inference Agent recovery state belongs to another host."
|
|
33247
34819
|
);
|
|
33248
34820
|
}
|
|
33249
34821
|
let state;
|
|
33250
34822
|
if (recoveredState?.schema_version === "vtx_codex_agent_runtime_v1") {
|
|
34823
|
+
if (this.options.adapterId !== "codex") {
|
|
34824
|
+
throw new InferenceHostRunnerError(
|
|
34825
|
+
"agent_recovery_adapter_mismatch",
|
|
34826
|
+
"Legacy Codex Agent recovery state cannot be opened by another adapter."
|
|
34827
|
+
);
|
|
34828
|
+
}
|
|
33251
34829
|
state = await this.upgradeLegacyRuntimeState(recoveredState, signal);
|
|
33252
34830
|
if (!state) return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
34831
|
+
} else if (recoveredState?.schema_version === "vtx_codex_agent_runtime_v2") {
|
|
34832
|
+
if (this.options.adapterId !== "codex") {
|
|
34833
|
+
throw new InferenceHostRunnerError(
|
|
34834
|
+
"agent_recovery_adapter_mismatch",
|
|
34835
|
+
"Legacy Codex Agent recovery state cannot be opened by another adapter."
|
|
34836
|
+
);
|
|
34837
|
+
}
|
|
34838
|
+
state = {
|
|
34839
|
+
...recoveredState,
|
|
34840
|
+
schema_version: "vtx_inference_agent_runtime_v3",
|
|
34841
|
+
adapter_id: "codex"
|
|
34842
|
+
};
|
|
34843
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33253
34844
|
} else {
|
|
33254
34845
|
state = recoveredState ?? null;
|
|
34846
|
+
if (state && state.adapter_id !== this.options.adapterId) {
|
|
34847
|
+
throw new InferenceHostRunnerError(
|
|
34848
|
+
"agent_recovery_adapter_mismatch",
|
|
34849
|
+
"Inference Agent recovery state belongs to another adapter."
|
|
34850
|
+
);
|
|
34851
|
+
}
|
|
33255
34852
|
}
|
|
33256
34853
|
if (!state) {
|
|
33257
34854
|
const assignment2 = await this.options.controlClient.nextAssignment({
|
|
33258
|
-
operation_id:
|
|
34855
|
+
operation_id: randomUUID3(),
|
|
33259
34856
|
host_id: this.options.hostId,
|
|
33260
34857
|
requested_at: nowIso()
|
|
33261
34858
|
}, { signal });
|
|
33262
34859
|
if (!assignment2) return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
33263
34860
|
state = {
|
|
33264
|
-
schema_version: "
|
|
34861
|
+
schema_version: "vtx_inference_agent_runtime_v3",
|
|
34862
|
+
adapter_id: this.options.adapterId,
|
|
33265
34863
|
host_id: this.options.hostId,
|
|
33266
34864
|
assignment: assignment2,
|
|
33267
34865
|
thread: null,
|
|
@@ -33269,7 +34867,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33269
34867
|
pending_decision: null,
|
|
33270
34868
|
updated_at: nowIso()
|
|
33271
34869
|
};
|
|
33272
|
-
await
|
|
34870
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33273
34871
|
} else {
|
|
33274
34872
|
const persistedWakeAtMs = Date.parse(state.next_wake_at);
|
|
33275
34873
|
if (persistedWakeAtMs > this.now()) {
|
|
@@ -33277,8 +34875,8 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33277
34875
|
if (wakeOutcome !== "ready") {
|
|
33278
34876
|
return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
33279
34877
|
}
|
|
33280
|
-
const rereadState = await
|
|
33281
|
-
if (rereadState?.schema_version !== "
|
|
34878
|
+
const rereadState = await readInferenceAgentRuntimeState(this.options.statePath);
|
|
34879
|
+
if (rereadState?.schema_version !== "vtx_inference_agent_runtime_v3" || rereadState.adapter_id !== this.options.adapterId) {
|
|
33282
34880
|
return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
33283
34881
|
}
|
|
33284
34882
|
state = rereadState;
|
|
@@ -33287,7 +34885,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33287
34885
|
state = await this.resolvePendingDecision(state, signal);
|
|
33288
34886
|
let assignment = state.assignment;
|
|
33289
34887
|
const preTurnHeartbeat = await this.options.controlClient.heartbeat({
|
|
33290
|
-
operation_id:
|
|
34888
|
+
operation_id: randomUUID3(),
|
|
33291
34889
|
host_id: this.options.hostId,
|
|
33292
34890
|
assignment_id: assignment.assignment_id,
|
|
33293
34891
|
assignment_generation: assignment.assignment_generation,
|
|
@@ -33302,7 +34900,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33302
34900
|
lease_expires_at: preTurnHeartbeat.lease_expires_at
|
|
33303
34901
|
};
|
|
33304
34902
|
state = { ...state, assignment, updated_at: nowIso() };
|
|
33305
|
-
await
|
|
34903
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33306
34904
|
const turnAbort = new AbortController();
|
|
33307
34905
|
const relayAbort = () => turnAbort.abort();
|
|
33308
34906
|
signal?.addEventListener("abort", relayAbort, { once: true });
|
|
@@ -33312,7 +34910,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33312
34910
|
const heartbeatTask = (async () => {
|
|
33313
34911
|
while (!heartbeatStopped && !turnAbort.signal.aborted) {
|
|
33314
34912
|
const heartbeat = await this.options.controlClient.heartbeat({
|
|
33315
|
-
operation_id:
|
|
34913
|
+
operation_id: randomUUID3(),
|
|
33316
34914
|
host_id: this.options.hostId,
|
|
33317
34915
|
assignment_id: assignment.assignment_id,
|
|
33318
34916
|
assignment_generation: assignment.assignment_generation,
|
|
@@ -33336,7 +34934,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33336
34934
|
const deadlineAtMs = this.now() + (this.options.turnTimeoutMs ?? 10 * 6e4);
|
|
33337
34935
|
const result2 = await this.options.adapter.runTurn({
|
|
33338
34936
|
durableThread: state.thread,
|
|
33339
|
-
systemPrompt:
|
|
34937
|
+
systemPrompt: INFERENCE_AGENT_SYSTEM_PROMPT,
|
|
33340
34938
|
userPrompt: JSON.stringify({
|
|
33341
34939
|
assignment_id: assignment.assignment_id,
|
|
33342
34940
|
assignment_generation: assignment.assignment_generation,
|
|
@@ -33350,7 +34948,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33350
34948
|
maximum: assignment.maximum_wake_seconds
|
|
33351
34949
|
}
|
|
33352
34950
|
}),
|
|
33353
|
-
outputSchema:
|
|
34951
|
+
outputSchema: INFERENCE_AGENT_WAKE_SCHEMA,
|
|
33354
34952
|
dataContract: assignment.data_contract,
|
|
33355
34953
|
decisionSchema: assignment.output_schema,
|
|
33356
34954
|
requestedModel: assignment.model_id,
|
|
@@ -33359,7 +34957,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33359
34957
|
signal: turnAbort.signal,
|
|
33360
34958
|
onThreadReady: async (thread) => {
|
|
33361
34959
|
state = { ...state, thread, updated_at: nowIso() };
|
|
33362
|
-
await
|
|
34960
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33363
34961
|
},
|
|
33364
34962
|
executeTool: async (call) => {
|
|
33365
34963
|
if (call.tool === "vtx_get_data") {
|
|
@@ -33369,7 +34967,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33369
34967
|
return { success: false, value: { error: "invalid_data_request" } };
|
|
33370
34968
|
}
|
|
33371
34969
|
const value = await this.options.controlClient.dataCall({
|
|
33372
|
-
operation_id:
|
|
34970
|
+
operation_id: randomUUID3(),
|
|
33373
34971
|
host_id: this.options.hostId,
|
|
33374
34972
|
assignment_id: assignment.assignment_id,
|
|
33375
34973
|
assignment_generation: assignment.assignment_generation,
|
|
@@ -33393,12 +34991,12 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33393
34991
|
return { success: false, value: { error: "decision_outcome_unresolved" } };
|
|
33394
34992
|
}
|
|
33395
34993
|
const pending = {
|
|
33396
|
-
operation_id:
|
|
34994
|
+
operation_id: randomUUID3(),
|
|
33397
34995
|
candidate,
|
|
33398
34996
|
observed_at: nowIso(),
|
|
33399
34997
|
provenance: {
|
|
33400
|
-
source: "
|
|
33401
|
-
|
|
34998
|
+
source: "external_agent",
|
|
34999
|
+
agent_run_id: liveThread.threadId,
|
|
33402
35000
|
requested_model: assignment.model_id,
|
|
33403
35001
|
effective_model: liveThread.effectiveModel,
|
|
33404
35002
|
requested_reasoning_effort: assignment.reasoning_effort,
|
|
@@ -33408,13 +35006,13 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33408
35006
|
last_status_check_at: null
|
|
33409
35007
|
};
|
|
33410
35008
|
state = { ...state, pending_decision: pending, updated_at: nowIso() };
|
|
33411
|
-
await
|
|
35009
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33412
35010
|
state = {
|
|
33413
35011
|
...state,
|
|
33414
35012
|
pending_decision: { ...pending, first_transmit_at: nowIso() },
|
|
33415
35013
|
updated_at: nowIso()
|
|
33416
35014
|
};
|
|
33417
|
-
await
|
|
35015
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33418
35016
|
let submitStatus;
|
|
33419
35017
|
try {
|
|
33420
35018
|
submitStatus = await this.options.controlClient.submitDecision({
|
|
@@ -33431,7 +35029,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33431
35029
|
}
|
|
33432
35030
|
if (submitStatus.status === "applied" || submitStatus.status === "not_applied") {
|
|
33433
35031
|
state = { ...state, pending_decision: null, updated_at: nowIso() };
|
|
33434
|
-
await
|
|
35032
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33435
35033
|
}
|
|
33436
35034
|
return {
|
|
33437
35035
|
success: submitStatus.status === "applied",
|
|
@@ -33455,7 +35053,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33455
35053
|
pending_decision: null,
|
|
33456
35054
|
updated_at: nowIso()
|
|
33457
35055
|
};
|
|
33458
|
-
await
|
|
35056
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33459
35057
|
}
|
|
33460
35058
|
return {
|
|
33461
35059
|
success: status.status === "applied" || status.status === "not_applied",
|
|
@@ -33463,11 +35061,11 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33463
35061
|
};
|
|
33464
35062
|
}
|
|
33465
35063
|
});
|
|
33466
|
-
const wakeSeconds =
|
|
35064
|
+
const wakeSeconds = parseInferenceAgentWake(result2.turn.text, assignment);
|
|
33467
35065
|
const nextWakeAtMs = this.now() + wakeSeconds * 1e3;
|
|
33468
35066
|
const scheduledWakeAt = new Date(nextWakeAtMs).toISOString();
|
|
33469
35067
|
const wakeHeartbeat = await this.options.controlClient.heartbeat({
|
|
33470
|
-
operation_id:
|
|
35068
|
+
operation_id: randomUUID3(),
|
|
33471
35069
|
host_id: this.options.hostId,
|
|
33472
35070
|
assignment_id: assignment.assignment_id,
|
|
33473
35071
|
assignment_generation: assignment.assignment_generation,
|
|
@@ -33477,7 +35075,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33477
35075
|
if (wakeHeartbeat.directive === "cancel") {
|
|
33478
35076
|
if (state.pending_decision) return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
33479
35077
|
await this.options.adapter.releaseThread(result2.thread).catch(() => void 0);
|
|
33480
|
-
await
|
|
35078
|
+
await clearInferenceAgentRuntimeState(this.options.statePath);
|
|
33481
35079
|
return this.now() + (this.options.idlePollMs ?? 5e3);
|
|
33482
35080
|
}
|
|
33483
35081
|
latestLeaseExpiry = wakeHeartbeat.lease_expires_at;
|
|
@@ -33488,7 +35086,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33488
35086
|
next_wake_at: scheduledWakeAt,
|
|
33489
35087
|
updated_at: nowIso()
|
|
33490
35088
|
};
|
|
33491
|
-
await
|
|
35089
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
33492
35090
|
return nextWakeAtMs;
|
|
33493
35091
|
} catch (error48) {
|
|
33494
35092
|
if (!cancelled) throw error48;
|
|
@@ -33507,7 +35105,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33507
35105
|
if (state.thread) {
|
|
33508
35106
|
await this.options.adapter.releaseThread(state.thread).catch(() => void 0);
|
|
33509
35107
|
}
|
|
33510
|
-
await
|
|
35108
|
+
await clearInferenceAgentRuntimeState(this.options.statePath);
|
|
33511
35109
|
return null;
|
|
33512
35110
|
}
|
|
33513
35111
|
async resolveLegacyPendingDecision(state, signal) {
|
|
@@ -33519,7 +35117,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33519
35117
|
pending_decision: { ...pending, last_status_check_at: checkedAt },
|
|
33520
35118
|
updated_at: checkedAt
|
|
33521
35119
|
};
|
|
33522
|
-
await
|
|
35120
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, checking);
|
|
33523
35121
|
const status = await this.options.controlClient.decisionStatus({
|
|
33524
35122
|
host_id: this.options.hostId,
|
|
33525
35123
|
assignment_id: state.assignment.assignment_id,
|
|
@@ -33532,7 +35130,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33532
35130
|
pending_decision: null,
|
|
33533
35131
|
updated_at: new Date(this.now()).toISOString()
|
|
33534
35132
|
};
|
|
33535
|
-
await
|
|
35133
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, resolved);
|
|
33536
35134
|
return resolved;
|
|
33537
35135
|
}
|
|
33538
35136
|
async resolvePendingDecision(state, signal) {
|
|
@@ -33544,7 +35142,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33544
35142
|
pending_decision: { ...pending, last_status_check_at: checkedAt },
|
|
33545
35143
|
updated_at: checkedAt
|
|
33546
35144
|
};
|
|
33547
|
-
await
|
|
35145
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, checking);
|
|
33548
35146
|
const status = await this.options.controlClient.decisionStatus({
|
|
33549
35147
|
host_id: this.options.hostId,
|
|
33550
35148
|
assignment_id: state.assignment.assignment_id,
|
|
@@ -33557,7 +35155,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33557
35155
|
pending_decision: null,
|
|
33558
35156
|
updated_at: new Date(this.now()).toISOString()
|
|
33559
35157
|
};
|
|
33560
|
-
await
|
|
35158
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, resolved);
|
|
33561
35159
|
return resolved;
|
|
33562
35160
|
}
|
|
33563
35161
|
async handleCancelledAssignment(state, signal) {
|
|
@@ -33573,7 +35171,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33573
35171
|
if (current.thread) {
|
|
33574
35172
|
await this.options.adapter.releaseThread(current.thread).catch(() => void 0);
|
|
33575
35173
|
}
|
|
33576
|
-
await
|
|
35174
|
+
await clearInferenceAgentRuntimeState(this.options.statePath);
|
|
33577
35175
|
}
|
|
33578
35176
|
async waitUntilWake(nextWakeAtMs, signal) {
|
|
33579
35177
|
const heartbeatIntervalMs = this.options.heartbeatIntervalMs ?? 3e3;
|
|
@@ -33581,11 +35179,11 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33581
35179
|
await this.sleep(Math.min(heartbeatIntervalMs, nextWakeAtMs - this.now()), signal);
|
|
33582
35180
|
if (this.stopped || signal?.aborted) return "stopped";
|
|
33583
35181
|
if (this.now() >= nextWakeAtMs) return "ready";
|
|
33584
|
-
const state = await
|
|
33585
|
-
if (state?.schema_version !== "
|
|
35182
|
+
const state = await readInferenceAgentRuntimeState(this.options.statePath);
|
|
35183
|
+
if (state?.schema_version !== "vtx_inference_agent_runtime_v3" || state.adapter_id !== this.options.adapterId) return "cancelled";
|
|
33586
35184
|
const requestedAt = new Date(this.now()).toISOString();
|
|
33587
35185
|
const heartbeat = await this.options.controlClient.heartbeat({
|
|
33588
|
-
operation_id:
|
|
35186
|
+
operation_id: randomUUID3(),
|
|
33589
35187
|
host_id: this.options.hostId,
|
|
33590
35188
|
assignment_id: state.assignment.assignment_id,
|
|
33591
35189
|
assignment_generation: state.assignment.assignment_generation,
|
|
@@ -33595,7 +35193,7 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33595
35193
|
await this.handleCancelledAssignment(state, signal);
|
|
33596
35194
|
return "cancelled";
|
|
33597
35195
|
}
|
|
33598
|
-
await
|
|
35196
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, {
|
|
33599
35197
|
...state,
|
|
33600
35198
|
assignment: {
|
|
33601
35199
|
...state.assignment,
|
|
@@ -33606,9 +35204,25 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33606
35204
|
}
|
|
33607
35205
|
return this.stopped || signal?.aborted ? "stopped" : "ready";
|
|
33608
35206
|
}
|
|
33609
|
-
async releaseForHostStop() {
|
|
33610
|
-
|
|
33611
|
-
if (!
|
|
35207
|
+
async releaseForHostStop(reasonCode = "host_stopped") {
|
|
35208
|
+
const recovered = await readInferenceAgentRuntimeState(this.options.statePath);
|
|
35209
|
+
if (!recovered) return;
|
|
35210
|
+
let state;
|
|
35211
|
+
if (recovered.schema_version === "vtx_codex_agent_runtime_v1") {
|
|
35212
|
+
if (this.options.adapterId !== "codex") return;
|
|
35213
|
+
state = recovered;
|
|
35214
|
+
} else if (recovered.schema_version === "vtx_codex_agent_runtime_v2") {
|
|
35215
|
+
if (this.options.adapterId !== "codex") return;
|
|
35216
|
+
state = {
|
|
35217
|
+
...recovered,
|
|
35218
|
+
schema_version: "vtx_inference_agent_runtime_v3",
|
|
35219
|
+
adapter_id: "codex"
|
|
35220
|
+
};
|
|
35221
|
+
await writeInferenceAgentRuntimeState(this.options.statePath, state);
|
|
35222
|
+
} else {
|
|
35223
|
+
if (recovered.adapter_id !== this.options.adapterId) return;
|
|
35224
|
+
state = recovered;
|
|
35225
|
+
}
|
|
33612
35226
|
try {
|
|
33613
35227
|
state = state.schema_version === "vtx_codex_agent_runtime_v1" ? await this.resolveLegacyPendingDecision(state) : await this.resolvePendingDecision(state);
|
|
33614
35228
|
} catch {
|
|
@@ -33616,15 +35230,15 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33616
35230
|
}
|
|
33617
35231
|
if (state.pending_decision) return;
|
|
33618
35232
|
await this.options.controlClient.releaseAssignment({
|
|
33619
|
-
operation_id:
|
|
35233
|
+
operation_id: randomUUID3(),
|
|
33620
35234
|
host_id: this.options.hostId,
|
|
33621
35235
|
assignment_id: state.assignment.assignment_id,
|
|
33622
35236
|
assignment_generation: state.assignment.assignment_generation,
|
|
33623
|
-
reason_code:
|
|
35237
|
+
reason_code: reasonCode,
|
|
33624
35238
|
requested_at: new Date(this.now()).toISOString()
|
|
33625
35239
|
}, {});
|
|
33626
35240
|
if (state.thread) await this.options.adapter.releaseThread(state.thread);
|
|
33627
|
-
await
|
|
35241
|
+
await clearInferenceAgentRuntimeState(this.options.statePath);
|
|
33628
35242
|
}
|
|
33629
35243
|
};
|
|
33630
35244
|
}
|
|
@@ -33632,11 +35246,11 @@ VTX supplies no trading prompt or prepared market context. At your own cadence,
|
|
|
33632
35246
|
|
|
33633
35247
|
// lib/inference-host/service.ts
|
|
33634
35248
|
import { spawn as spawn6 } from "node:child_process";
|
|
33635
|
-
import { randomUUID as
|
|
35249
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
33636
35250
|
import { createWriteStream, readFileSync } from "node:fs";
|
|
33637
|
-
import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as
|
|
35251
|
+
import { access as access3, chmod as chmod3, mkdir as mkdir3, readFile as readFile5, rm as rm6, writeFile as writeFile2 } from "node:fs/promises";
|
|
33638
35252
|
import { homedir as homedir2 } from "node:os";
|
|
33639
|
-
import { dirname as
|
|
35253
|
+
import { dirname as dirname5, join as join7, resolve as resolve4 } from "node:path";
|
|
33640
35254
|
var SERVICE_NAME, SYSTEMD_UNIT, LAUNCHD_LABEL, SERVICE_COOPERATIVE_STOP_SECONDS, INFERENCE_HOST_SERVICE_DRAIN_COMMAND, inferenceHostServiceChildEnvironment, isWindowsSubsystemForLinux, inferenceHostServiceManifestPath, inferenceHostServiceDesiredPath, inferenceHostServiceLogPath, inferenceHostServiceRuntimePath, xmlEscape, plistEscape, systemdQuote, defaultRunCommand, managerName, assertRuntimeEnvironment, withoutConcurrencyLimit, assertServicePath, manifestGeneration, assertWorker, assertManifest, assertServiceRuntimeState, assertDesiredState, readInferenceHostServiceManifest, readManifestAcrossAtomicReplacement, readInferenceHostServiceRuntime, readRuntimeAcrossAtomicReplacement, readInferenceHostServiceDesired, readDesiredAcrossAtomicReplacement, writeDesired, runtimeEnvironment, serviceArguments, windowsOwnedCommandLine, vbScriptString, windowsServiceLauncher, windowsTaskXml, systemdUnit, launchAgentPlist, sameWorker, sameServiceDefinition, sameWorkerSet, InferenceHostServiceManager, appendServiceLog, spawnInferenceHostServiceChild, runInferenceHostServiceSupervisor;
|
|
33641
35255
|
var init_service = __esm({
|
|
33642
35256
|
"lib/inference-host/service.ts"() {
|
|
@@ -34105,8 +35719,8 @@ WantedBy=default.target
|
|
|
34105
35719
|
}
|
|
34106
35720
|
definitionPath() {
|
|
34107
35721
|
if (this.platform === "win32") return `${this.config.supervisorStatePath}.service-task.xml`;
|
|
34108
|
-
if (this.platform === "darwin") return
|
|
34109
|
-
return
|
|
35722
|
+
if (this.platform === "darwin") return join7(this.home, "Library", "LaunchAgents", `${LAUNCHD_LABEL}.plist`);
|
|
35723
|
+
return join7(this.home, ".config", "systemd", "user", SYSTEMD_UNIT);
|
|
34110
35724
|
}
|
|
34111
35725
|
windowsLauncherPath() {
|
|
34112
35726
|
return `${this.config.supervisorStatePath}.service-launcher.vbs`;
|
|
@@ -34157,7 +35771,7 @@ WantedBy=default.target
|
|
|
34157
35771
|
const previousRuntimeUpdatedAt = previousRuntime?.manifest_generation === manifest.generation ? Date.parse(previousRuntime.updated_at) : Number.NaN;
|
|
34158
35772
|
const restoredManifest = preserveGeneration ? manifest : assertManifest({
|
|
34159
35773
|
...manifest,
|
|
34160
|
-
generation:
|
|
35774
|
+
generation: randomUUID4(),
|
|
34161
35775
|
installed_at: this.now().toISOString()
|
|
34162
35776
|
});
|
|
34163
35777
|
await writeAtomicInferencePrivateFile(
|
|
@@ -34239,7 +35853,7 @@ ${result2.stderr}`)) {
|
|
|
34239
35853
|
await writeAtomicInferencePrivateFile(this.manifestPath(), `${JSON.stringify(manifest, null, 2)}
|
|
34240
35854
|
`);
|
|
34241
35855
|
await writeDesired(this.desiredPath(), desiredRunning, this.now());
|
|
34242
|
-
await mkdir3(
|
|
35856
|
+
await mkdir3(dirname5(this.definitionPath()), { recursive: true, mode: 448 });
|
|
34243
35857
|
if (this.platform === "win32") {
|
|
34244
35858
|
await writeAtomicInferencePrivateFile(
|
|
34245
35859
|
this.windowsLauncherPath(),
|
|
@@ -34288,13 +35902,13 @@ ${cleanup.stderr}`)) {
|
|
|
34288
35902
|
);
|
|
34289
35903
|
}
|
|
34290
35904
|
}
|
|
34291
|
-
await
|
|
35905
|
+
await rm6(this.definitionPath(), { force: true }).catch(() => void 0);
|
|
34292
35906
|
if (this.platform === "win32") {
|
|
34293
|
-
await
|
|
35907
|
+
await rm6(this.windowsLauncherPath(), { force: true }).catch(() => void 0);
|
|
34294
35908
|
}
|
|
34295
|
-
await
|
|
34296
|
-
await
|
|
34297
|
-
await
|
|
35909
|
+
await rm6(this.manifestPath(), { force: true }).catch(() => void 0);
|
|
35910
|
+
await rm6(this.desiredPath(), { force: true }).catch(() => void 0);
|
|
35911
|
+
await rm6(this.runtimePath(), { force: true }).catch(() => void 0);
|
|
34298
35912
|
if (this.platform === "linux") {
|
|
34299
35913
|
await this.runCommand("systemctl", ["--user", "daemon-reload"]).catch(() => void 0);
|
|
34300
35914
|
}
|
|
@@ -34443,7 +36057,7 @@ ${cleanup.stderr}`)) {
|
|
|
34443
36057
|
].sort((left, right) => left.instance_name.localeCompare(right.instance_name));
|
|
34444
36058
|
const manifest = assertManifest({
|
|
34445
36059
|
schema_version: "vtx_inference_service_v3",
|
|
34446
|
-
generation:
|
|
36060
|
+
generation: randomUUID4(),
|
|
34447
36061
|
installed_at: this.now().toISOString(),
|
|
34448
36062
|
executable: this.executable,
|
|
34449
36063
|
script: this.script,
|
|
@@ -34657,7 +36271,7 @@ ${result2.stderr}`)) {
|
|
|
34657
36271
|
if (remaining.length === 0) return await this.uninstallUnlocked();
|
|
34658
36272
|
return await this.replaceManifestUnlocked({
|
|
34659
36273
|
...manifest,
|
|
34660
|
-
generation:
|
|
36274
|
+
generation: randomUUID4(),
|
|
34661
36275
|
installed_at: this.now().toISOString(),
|
|
34662
36276
|
workers: remaining
|
|
34663
36277
|
}, await readInferenceHostServiceDesired(this.desiredPath()));
|
|
@@ -34680,12 +36294,12 @@ ${result2.stderr}`)) {
|
|
|
34680
36294
|
${result2.stderr}`)) {
|
|
34681
36295
|
throw new Error(`Background service uninstall failed: ${result2.stderr.trim()}`);
|
|
34682
36296
|
}
|
|
34683
|
-
await
|
|
34684
|
-
if (this.platform === "win32") await
|
|
36297
|
+
await rm6(this.definitionPath(), { force: true });
|
|
36298
|
+
if (this.platform === "win32") await rm6(this.windowsLauncherPath(), { force: true });
|
|
34685
36299
|
if (this.platform === "linux") await this.runCommand("systemctl", ["--user", "daemon-reload"]);
|
|
34686
|
-
await
|
|
34687
|
-
await
|
|
34688
|
-
await
|
|
36300
|
+
await rm6(this.manifestPath(), { force: true });
|
|
36301
|
+
await rm6(this.desiredPath(), { force: true });
|
|
36302
|
+
await rm6(this.runtimePath(), { force: true });
|
|
34689
36303
|
return {
|
|
34690
36304
|
installed: false,
|
|
34691
36305
|
desired_running: false,
|
|
@@ -34699,7 +36313,7 @@ ${result2.stderr}`)) {
|
|
|
34699
36313
|
}
|
|
34700
36314
|
};
|
|
34701
36315
|
appendServiceLog = async (path, event, fields = {}) => {
|
|
34702
|
-
await mkdir3(
|
|
36316
|
+
await mkdir3(dirname5(path), { recursive: true, mode: 448 });
|
|
34703
36317
|
const stream = createWriteStream(path, { flags: "a", mode: 384 });
|
|
34704
36318
|
await new Promise((resolvePromise, reject) => {
|
|
34705
36319
|
stream.once("error", reject);
|
|
@@ -35047,11 +36661,11 @@ __export(cli_exports, {
|
|
|
35047
36661
|
registerInferenceHostServiceControlInput: () => registerInferenceHostServiceControlInput,
|
|
35048
36662
|
runInferenceHostCli: () => runInferenceHostCli
|
|
35049
36663
|
});
|
|
35050
|
-
import { createHash as
|
|
36664
|
+
import { createHash as createHash8, randomUUID as randomUUID5 } from "node:crypto";
|
|
35051
36665
|
import { spawn as spawn7 } from "node:child_process";
|
|
35052
|
-
import { lstat as lstat4, realpath as
|
|
36666
|
+
import { lstat as lstat4, realpath as realpath5, rm as rm7 } from "node:fs/promises";
|
|
35053
36667
|
import { hostname as osHostname } from "node:os";
|
|
35054
|
-
import { join as
|
|
36668
|
+
import { join as join8, resolve as resolve5 } from "node:path";
|
|
35055
36669
|
async function runInferenceHostCli(argv2, env = process.env, dependencies = {}) {
|
|
35056
36670
|
const warnings = [];
|
|
35057
36671
|
try {
|
|
@@ -35081,6 +36695,9 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
35081
36695
|
if (parsed.command === "codex-login") {
|
|
35082
36696
|
return await codexLogin(config2, parsed, env, dependencies);
|
|
35083
36697
|
}
|
|
36698
|
+
if (parsed.command === "deepseek-login") {
|
|
36699
|
+
return await deepSeekLogin(config2, parsed, dependencies);
|
|
36700
|
+
}
|
|
35084
36701
|
if (parsed.command === "run") {
|
|
35085
36702
|
return await runHost(config2, parsed, env, dependencies, warnings);
|
|
35086
36703
|
}
|
|
@@ -35111,6 +36728,42 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
35111
36728
|
async () => await agentFail(config2, parsed, dependencies, warnings)
|
|
35112
36729
|
);
|
|
35113
36730
|
}
|
|
36731
|
+
if (parsed.command === "agent-assignment-next") {
|
|
36732
|
+
return await withAgentCommandLock(
|
|
36733
|
+
config2,
|
|
36734
|
+
async () => await foregroundAssignmentNext(config2, parsed, dependencies, warnings)
|
|
36735
|
+
);
|
|
36736
|
+
}
|
|
36737
|
+
if (parsed.command === "agent-assignment-heartbeat") {
|
|
36738
|
+
return await withAgentCommandLock(
|
|
36739
|
+
config2,
|
|
36740
|
+
async () => await foregroundAssignmentHeartbeat(config2, parsed, dependencies, warnings)
|
|
36741
|
+
);
|
|
36742
|
+
}
|
|
36743
|
+
if (parsed.command === "agent-data-call") {
|
|
36744
|
+
return await withAgentCommandLock(
|
|
36745
|
+
config2,
|
|
36746
|
+
async () => await foregroundDataCall(config2, parsed, dependencies, warnings)
|
|
36747
|
+
);
|
|
36748
|
+
}
|
|
36749
|
+
if (parsed.command === "agent-decision-submit") {
|
|
36750
|
+
return await withAgentCommandLock(
|
|
36751
|
+
config2,
|
|
36752
|
+
async () => await foregroundDecisionSubmit(config2, parsed, dependencies, warnings)
|
|
36753
|
+
);
|
|
36754
|
+
}
|
|
36755
|
+
if (parsed.command === "agent-decision-status") {
|
|
36756
|
+
return await withAgentCommandLock(
|
|
36757
|
+
config2,
|
|
36758
|
+
async () => await foregroundDecisionStatus(config2, parsed, dependencies, warnings)
|
|
36759
|
+
);
|
|
36760
|
+
}
|
|
36761
|
+
if (parsed.command === "agent-assignment-release") {
|
|
36762
|
+
return await withAgentCommandLock(
|
|
36763
|
+
config2,
|
|
36764
|
+
async () => await foregroundAssignmentRelease(config2, parsed, dependencies, warnings)
|
|
36765
|
+
);
|
|
36766
|
+
}
|
|
35114
36767
|
if (parsed.command === "service") {
|
|
35115
36768
|
const mutationActions = /* @__PURE__ */ new Set(["install", "start", "stop", "recover", "uninstall"]);
|
|
35116
36769
|
if (!parsed.serviceAction || !mutationActions.has(parsed.serviceAction)) {
|
|
@@ -35137,11 +36790,14 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
35137
36790
|
if (parsed.command === "codex-logout") {
|
|
35138
36791
|
return await codexLogout(config2, parsed, env, dependencies);
|
|
35139
36792
|
}
|
|
36793
|
+
if (parsed.command === "deepseek-logout") {
|
|
36794
|
+
return await deepSeekLogout(config2, parsed, dependencies);
|
|
36795
|
+
}
|
|
35140
36796
|
if (parsed.command === "revoke") {
|
|
35141
36797
|
return await cleanupLogin(config2, parsed, dependencies, warnings, true);
|
|
35142
36798
|
}
|
|
35143
36799
|
throw new Error(
|
|
35144
|
-
"Usage: vtx inference-host <login|codex-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|service|status|doctor|logout|codex-logout|revoke> [--json]"
|
|
36800
|
+
"Usage: vtx inference-host <login|codex-login|deepseek-login|run|agent-connect|agent-run|agent-next|agent-complete|agent-fail|agent-assignment-next|agent-assignment-heartbeat|agent-data-call|agent-decision-submit|agent-decision-status|agent-assignment-release|service|status|doctor|logout|codex-logout|deepseek-logout|revoke> [--json]"
|
|
35145
36801
|
);
|
|
35146
36802
|
} catch (error48) {
|
|
35147
36803
|
return {
|
|
@@ -35152,7 +36808,7 @@ async function runInferenceHostCli(argv2, env = process.env, dependencies = {})
|
|
|
35152
36808
|
};
|
|
35153
36809
|
}
|
|
35154
36810
|
}
|
|
35155
|
-
var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, credentialLifecycleLockPath, serviceRecoveryCommandLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parseHostConcurrency, parseInferenceHostArgs, resolveDurableServiceDisplayName, defaultOpenBrowser, registerInferenceHostServiceControlInput, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, restoreInferenceHostCredentialContext, recoverInferenceHostCredentialContextTransition, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, preparePortableDurableAdapter, defaultRunPortableDurableAdapter, login, codexLogin, codexLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, agentOperationId, agentSession, agentConnect, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, recoveryBackupPath, serviceRecoveryTransactionPath, readServiceRecoveryTransaction, assertResumableCodexRecoveryEvidence, recoverInstalledCodexService, serviceCommand, hasExplicitCredentialStoreConfiguration, credentialEnvironmentForIdentity, commandRequiresRetainedCredentialStore, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
|
|
36811
|
+
var INFERENCE_HOST_CLI_VERSION, runtimeReceiptPath, codexRecoveryPath, codexGuardianReceiptRoot, revocationCheckpointPath, foregroundHostLockPath, credentialLifecycleLockPath, serviceRecoveryCommandLockPath, AGENT_HEARTBEAT_INTERVAL_MS, AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS, retryableAgentHeartbeatError, assertRevocationCheckpoint, readRevocationCheckpoint, writeRevocationCheckpoint, clearRevocationCheckpoint, render, INFERENCE_HOST_HELP, parseHostConcurrency, parseInferenceHostArgs, resolveDurableServiceDisplayName, defaultOpenBrowser, registerInferenceHostServiceControlInput, defaultRegisterLifecycleSignalHandlers, lifecycleCancellation, configuredCredentialStore, restoreInferenceHostCredentialContext, recoverInferenceHostCredentialContextTransition, accountKeyForState, assertCredentialMatchesState2, revocationCheckpointForCredential, assertRevocationCheckpointMatchesLocalIdentity, fileExistsPrivately, inspectCodexAuthentication, clearLocalRuntimeArtifacts, assertDurableServiceUninstalled, assertLocalRuntimeArtifactsMayBeDiscarded, defaultRunForeground, preparePortableDurableAdapter, defaultRunPortableDurableAdapter, login, codexLogin, codexLogout, deepSeekCredentialStore, deepSeekLogin, deepSeekLogout, localStatus, doctor, cleanupLogin, runHost, defaultReadStdin, parseAgentStdin, parseOptionalAgentStdin, agentOperationId, agentSession, agentConnect, foregroundAgentControlState, requireForegroundAgentState, assignmentFromClaim, foregroundAssignmentNext, foregroundAssignmentHeartbeat, foregroundDataCall, foregroundDecisionStatusRequest, foregroundAssignmentLeaseEnded, handleForegroundCancelledAssignment, foregroundDecisionStatus, foregroundDecisionSubmit, foregroundAssignmentRelease, agentRun, agentNext, agentComplete, agentFail, withAgentCommandLock, recoveryBackupPath, serviceRecoveryTransactionPath, readServiceRecoveryTransaction, assertResumableCodexRecoveryEvidence, recoverInstalledCodexService, serviceCommand, hasExplicitCredentialStoreConfiguration, credentialEnvironmentForIdentity, commandRequiresRetainedCredentialStore, commandUsesInstalledServiceCredentials, resolveInferenceHostCommandConfig;
|
|
35156
36812
|
var init_cli = __esm({
|
|
35157
36813
|
"lib/inference-host/cli.ts"() {
|
|
35158
36814
|
"use strict";
|
|
@@ -35163,6 +36819,8 @@ var init_cli = __esm({
|
|
|
35163
36819
|
init_codex_adapter();
|
|
35164
36820
|
init_codex_recovery_process();
|
|
35165
36821
|
init_copilot_adapter();
|
|
36822
|
+
init_deepseek_harness_adapter();
|
|
36823
|
+
init_deepseek_credential_store();
|
|
35166
36824
|
init_durable_adapter();
|
|
35167
36825
|
init_codex_app_server();
|
|
35168
36826
|
init_codex_binary();
|
|
@@ -35246,23 +36904,31 @@ var init_cli = __esm({
|
|
|
35246
36904
|
Commands:
|
|
35247
36905
|
login Authorize the isolated VTX insights:inference grant
|
|
35248
36906
|
codex-login Sign the automated Codex host into a ChatGPT subscription
|
|
36907
|
+
deepseek-login Import a DeepSeek API key privately from stdin
|
|
35249
36908
|
run Run a supported durable inference adapter in the foreground
|
|
35250
36909
|
agent-connect Advertise a model from a compatible agent harness
|
|
35251
36910
|
agent-run Keep an agent-driven host online in the foreground
|
|
35252
36911
|
agent-next Claim the next exact VTX inference request
|
|
35253
36912
|
agent-complete Submit one completed agent result from stdin
|
|
35254
36913
|
agent-fail Submit one truthful agent failure from stdin
|
|
36914
|
+
agent-assignment-next Claim the assigned Main bot for Agent control
|
|
36915
|
+
agent-assignment-heartbeat Renew the current Agent assignment
|
|
36916
|
+
agent-data-call Request allowed assignment-scoped VTX data
|
|
36917
|
+
agent-decision-submit Submit the normal structured trading decision
|
|
36918
|
+
agent-decision-status Resolve an uncertain Agent decision submission
|
|
36919
|
+
agent-assignment-release Release the current Agent assignment
|
|
35255
36920
|
service Install and control the durable background host
|
|
35256
36921
|
status Inspect local host and credential state
|
|
35257
36922
|
doctor Verify credentials, provider runtime, and private state
|
|
35258
36923
|
logout Remove local VTX host state without revoking the grant
|
|
35259
36924
|
revoke Revoke the VTX grant and remove local host state
|
|
35260
36925
|
codex-logout Remove the automated host's dedicated Codex login
|
|
36926
|
+
deepseek-logout Remove the locally stored DeepSeek API key
|
|
35261
36927
|
|
|
35262
36928
|
Common options:
|
|
35263
36929
|
--json Emit machine-readable JSON
|
|
35264
36930
|
--instance NAME Target an isolated local subscription instance (default: default)
|
|
35265
|
-
--adapter ID Durable adapter: codex or
|
|
36931
|
+
--adapter ID Durable adapter: codex, copilot, or deepseek-harness
|
|
35266
36932
|
--max-concurrency N Optional positive-integer local slot limit (default: unlimited)
|
|
35267
36933
|
--help, -h Show this help
|
|
35268
36934
|
|
|
@@ -35278,6 +36944,8 @@ Durable service:
|
|
|
35278
36944
|
vtx inference-host codex-login --instance codex-2
|
|
35279
36945
|
vtx inference-host service install --instance codex-2
|
|
35280
36946
|
vtx inference-host service install --adapter copilot --instance copilot-1
|
|
36947
|
+
vtx inference-host deepseek-login --instance deepseek-1 < /private/path/deepseek.key
|
|
36948
|
+
vtx inference-host service install --adapter deepseek-harness --instance deepseek-1
|
|
35281
36949
|
vtx inference-host service uninstall --instance codex-2
|
|
35282
36950
|
vtx inference-host service recover --instance codex-1 --force-recovery
|
|
35283
36951
|
vtx inference-host service <start|stop|status|logs|recover|uninstall>
|
|
@@ -35384,7 +37052,7 @@ Durable service:
|
|
|
35384
37052
|
if (command === "agent-connect" && !displayNameExplicit) {
|
|
35385
37053
|
displayName = "Agent-driven inference host";
|
|
35386
37054
|
} else if (adapter && isDurableInferenceAdapterId(adapter) && !displayNameExplicit) {
|
|
35387
|
-
displayName = `${durableAdapterDisplayName(adapter)}
|
|
37055
|
+
displayName = `${durableAdapterDisplayName(adapter)} host`;
|
|
35388
37056
|
}
|
|
35389
37057
|
return {
|
|
35390
37058
|
command,
|
|
@@ -35541,10 +37209,10 @@ Durable service:
|
|
|
35541
37209
|
return raw !== null;
|
|
35542
37210
|
};
|
|
35543
37211
|
inspectCodexAuthentication = async (config2) => {
|
|
35544
|
-
const path =
|
|
37212
|
+
const path = join8(config2.codexHomePath, "auth.json");
|
|
35545
37213
|
try {
|
|
35546
37214
|
const before = await lstat4(path);
|
|
35547
|
-
const canonical = await
|
|
37215
|
+
const canonical = await realpath5(path);
|
|
35548
37216
|
const isPrivate = before.isFile() && !before.isSymbolicLink() && canonical === resolve5(path) && before.size <= 8 * 1024 * 1024 && (process.platform === "win32" || (before.mode & 63) === 0 && (typeof process.getuid !== "function" || before.uid === process.getuid()));
|
|
35549
37217
|
return { present: true, private: isPrivate };
|
|
35550
37218
|
} catch (error48) {
|
|
@@ -35559,14 +37227,16 @@ Durable service:
|
|
|
35559
37227
|
runtimeReceiptPath(config2),
|
|
35560
37228
|
"Inference host runtime receipt file"
|
|
35561
37229
|
);
|
|
35562
|
-
await
|
|
37230
|
+
await rm7(codexGuardianReceiptRoot(config2), { recursive: true, force: true });
|
|
35563
37231
|
await clearInferencePrivateFile(
|
|
35564
37232
|
codexRecoveryPath(config2),
|
|
35565
37233
|
"Codex attempt recovery file"
|
|
35566
37234
|
);
|
|
35567
37235
|
await clearInferenceAgentAttemptState(config2.statePath);
|
|
35568
37236
|
await clearInferenceAgentNextState(config2.statePath);
|
|
37237
|
+
await clearInferenceForegroundAgentControlState(config2.statePath);
|
|
35569
37238
|
await clearCodexAgentRuntimeState(config2.statePath);
|
|
37239
|
+
await clearInferenceAgentFailureFence(config2.statePath);
|
|
35570
37240
|
await clearInferenceHostLocalState(config2.statePath);
|
|
35571
37241
|
};
|
|
35572
37242
|
assertDurableServiceUninstalled = async (config2) => {
|
|
@@ -35593,10 +37263,12 @@ Durable service:
|
|
|
35593
37263
|
const revocationCheckpointPresent = await readRevocationCheckpoint(config2) !== null;
|
|
35594
37264
|
const agentAttemptPresent = await readInferenceAgentAttemptState(config2.statePath) !== null;
|
|
35595
37265
|
const agentNextRecoveryPresent = await readInferenceAgentNextState(config2.statePath) !== null;
|
|
37266
|
+
const foregroundAgentControlPresent = await readInferenceForegroundAgentControlState(config2.statePath) !== null;
|
|
35596
37267
|
const codexAgentRuntimePresent = await readCodexAgentRuntimeState(config2.statePath) !== null;
|
|
35597
|
-
|
|
37268
|
+
const agentFailureFencePresent = await readInferenceAgentFailureFence(config2.statePath) !== null;
|
|
37269
|
+
if (pendingAttempts > 0 || codexRecoveryPresent || serviceRecoveryPresent || revocationCheckpointPresent || agentAttemptPresent || agentNextRecoveryPresent || foregroundAgentControlPresent || codexAgentRuntimePresent || agentFailureFencePresent) {
|
|
35598
37270
|
throw new Error(
|
|
35599
|
-
"Inference host logout refused because attempt recovery is still pending (Codex,
|
|
37271
|
+
"Inference host logout refused because attempt recovery is still pending (Codex, Provider, Agent-control, or revocation recovery). Reconcile or release the exact active operation before retrying logout, or resume revoke."
|
|
35600
37272
|
);
|
|
35601
37273
|
}
|
|
35602
37274
|
};
|
|
@@ -35664,11 +37336,19 @@ Durable service:
|
|
|
35664
37336
|
signal: options.signal
|
|
35665
37337
|
}).run();
|
|
35666
37338
|
};
|
|
35667
|
-
preparePortableDurableAdapter = async (adapterId, signal) => {
|
|
35668
|
-
const adapter = new CopilotSubscriptionAdapter()
|
|
37339
|
+
preparePortableDurableAdapter = async (adapterId, config2, signal) => {
|
|
37340
|
+
const adapter = adapterId === "copilot" ? new CopilotSubscriptionAdapter() : new DeepSeekHarnessAdapter({
|
|
37341
|
+
credentialStore: createDeepSeekHarnessCredentialStore(config2)
|
|
37342
|
+
});
|
|
35669
37343
|
return { adapter, preflight: await adapter.preflight(signal) };
|
|
35670
37344
|
};
|
|
35671
37345
|
defaultRunPortableDurableAdapter = async (options) => {
|
|
37346
|
+
const agentAdapter = options.adapter;
|
|
37347
|
+
if (typeof agentAdapter.runTurn !== "function" || typeof agentAdapter.releaseThread !== "function" || typeof agentAdapter.close !== "function") {
|
|
37348
|
+
throw new Error(
|
|
37349
|
+
`${options.preflight.adapterId} does not implement the durable Agent-control contract.`
|
|
37350
|
+
);
|
|
37351
|
+
}
|
|
35672
37352
|
const dependencies = createDefaultInferenceHostRunnerDependencies({
|
|
35673
37353
|
apiUrl: options.config.apiUrl,
|
|
35674
37354
|
statePath: options.config.statePath,
|
|
@@ -35704,6 +37384,10 @@ Durable service:
|
|
|
35704
37384
|
maxConcurrency: options.maxConcurrency,
|
|
35705
37385
|
once: options.once,
|
|
35706
37386
|
emitDiagnosticEvent: options.emitDiagnosticEvent,
|
|
37387
|
+
agentRuntime: {
|
|
37388
|
+
statePath: options.config.statePath,
|
|
37389
|
+
adapter: agentAdapter
|
|
37390
|
+
},
|
|
35707
37391
|
signal: options.signal
|
|
35708
37392
|
}).run();
|
|
35709
37393
|
};
|
|
@@ -35737,7 +37421,7 @@ Durable service:
|
|
|
35737
37421
|
await writeInferenceHostCredentialContextTransition(config2, previousCredentialContext);
|
|
35738
37422
|
await writeInferenceHostCredentialContext(config2);
|
|
35739
37423
|
const keyPair = generateExternalInferenceEnvelopeKeyPair();
|
|
35740
|
-
const hostId =
|
|
37424
|
+
const hostId = randomUUID5();
|
|
35741
37425
|
const beginLogin = dependencies.beginLogin ?? beginInferenceOAuthLogin;
|
|
35742
37426
|
const loginStore = {
|
|
35743
37427
|
kind: store.kind,
|
|
@@ -35935,6 +37619,53 @@ Waiting for approval...
|
|
|
35935
37619
|
cancellation.unregister();
|
|
35936
37620
|
}
|
|
35937
37621
|
};
|
|
37622
|
+
deepSeekCredentialStore = (config2, dependencies) => dependencies.createDeepSeekCredentialStore?.(config2) ?? createDeepSeekHarnessCredentialStore(config2);
|
|
37623
|
+
deepSeekLogin = async (config2, parsed, dependencies) => {
|
|
37624
|
+
await assertDurableServiceUninstalled(config2);
|
|
37625
|
+
if (!dependencies.readStdin && process.stdin.isTTY) {
|
|
37626
|
+
throw new Error("DeepSeek API key must be supplied through stdin, never as an argument.");
|
|
37627
|
+
}
|
|
37628
|
+
const cancellation = lifecycleCancellation(dependencies);
|
|
37629
|
+
let lock2 = null;
|
|
37630
|
+
try {
|
|
37631
|
+
lock2 = await acquireInferenceHostProcessLock(config2.processLockPath);
|
|
37632
|
+
const raw = await (dependencies.readStdin ?? defaultReadStdin)();
|
|
37633
|
+
const credential = await deepSeekCredentialStore(config2, dependencies).write(
|
|
37634
|
+
raw,
|
|
37635
|
+
cancellation.signal
|
|
37636
|
+
);
|
|
37637
|
+
const failureFence = await readInferenceAgentFailureFence(config2.statePath);
|
|
37638
|
+
if (failureFence?.adapter_id === "deepseek-harness" && failureFence.failure_category === "auth") {
|
|
37639
|
+
await clearInferenceAgentFailureFence(config2.statePath);
|
|
37640
|
+
}
|
|
37641
|
+
return {
|
|
37642
|
+
exitCode: 0,
|
|
37643
|
+
stdout: render({
|
|
37644
|
+
status: "deepseek_api_key_imported",
|
|
37645
|
+
identity: credential.identity,
|
|
37646
|
+
credential_store: config2.credentialStoreMode
|
|
37647
|
+
}, parsed.json),
|
|
37648
|
+
stderr: ""
|
|
37649
|
+
};
|
|
37650
|
+
} finally {
|
|
37651
|
+
await lock2?.release();
|
|
37652
|
+
cancellation.unregister();
|
|
37653
|
+
}
|
|
37654
|
+
};
|
|
37655
|
+
deepSeekLogout = async (config2, parsed, dependencies) => {
|
|
37656
|
+
await assertDurableServiceUninstalled(config2);
|
|
37657
|
+
const lock2 = await acquireInferenceHostProcessLock(config2.processLockPath);
|
|
37658
|
+
try {
|
|
37659
|
+
await deepSeekCredentialStore(config2, dependencies).remove();
|
|
37660
|
+
return {
|
|
37661
|
+
exitCode: 0,
|
|
37662
|
+
stdout: render({ status: "deepseek_api_key_removed" }, parsed.json),
|
|
37663
|
+
stderr: ""
|
|
37664
|
+
};
|
|
37665
|
+
} finally {
|
|
37666
|
+
await lock2.release();
|
|
37667
|
+
}
|
|
37668
|
+
};
|
|
35938
37669
|
localStatus = async (config2, parsed, dependencies, warnings) => {
|
|
35939
37670
|
const codexAuthentication = await inspectCodexAuthentication(config2);
|
|
35940
37671
|
const state = await readInferenceHostLocalState(config2.statePath);
|
|
@@ -35979,6 +37710,7 @@ Waiting for approval...
|
|
|
35979
37710
|
);
|
|
35980
37711
|
const agentAttempt = await readInferenceAgentAttemptState(config2.statePath);
|
|
35981
37712
|
const agentNextRecoveryPresent = await readInferenceAgentNextState(config2.statePath) !== null;
|
|
37713
|
+
const agentFailureFence = await readInferenceAgentFailureFence(config2.statePath);
|
|
35982
37714
|
return {
|
|
35983
37715
|
exitCode: 0,
|
|
35984
37716
|
stdout: render({
|
|
@@ -36004,6 +37736,13 @@ Waiting for approval...
|
|
|
36004
37736
|
deadline_at: agentAttempt.deadline_at
|
|
36005
37737
|
} : null,
|
|
36006
37738
|
agent_next_recovery_present: agentNextRecoveryPresent,
|
|
37739
|
+
agent_failure_fence: agentFailureFence ? {
|
|
37740
|
+
adapter: agentFailureFence.adapter_id,
|
|
37741
|
+
failure_category: agentFailureFence.failure_category,
|
|
37742
|
+
failure_code: agentFailureFence.failure_code,
|
|
37743
|
+
dispatch_outcome: agentFailureFence.dispatch_outcome,
|
|
37744
|
+
retry_at: agentFailureFence.retry_at
|
|
37745
|
+
} : null,
|
|
36007
37746
|
codex_recovery_present: recoveryPresent,
|
|
36008
37747
|
service_recovery_present: serviceRecoveryPresent,
|
|
36009
37748
|
codex_auth: codexAuthentication,
|
|
@@ -36022,6 +37761,12 @@ Waiting for approval...
|
|
|
36022
37761
|
ok: state !== null,
|
|
36023
37762
|
detail: state ? "valid" : "missing"
|
|
36024
37763
|
});
|
|
37764
|
+
const agentFailureFence = await readInferenceAgentFailureFence(config2.statePath);
|
|
37765
|
+
checks.push({
|
|
37766
|
+
name: "agent_runtime_fence",
|
|
37767
|
+
ok: agentFailureFence === null,
|
|
37768
|
+
detail: agentFailureFence === null ? "clear" : `${agentFailureFence.failure_code}:${agentFailureFence.dispatch_outcome}`
|
|
37769
|
+
});
|
|
36025
37770
|
checks.push({
|
|
36026
37771
|
name: "revocation_recovery",
|
|
36027
37772
|
ok: revocationCheckpoint === null,
|
|
@@ -36060,7 +37805,8 @@ Waiting for approval...
|
|
|
36060
37805
|
} else if (adapterId !== "codex") {
|
|
36061
37806
|
try {
|
|
36062
37807
|
const prepared = await (dependencies.prepareDurableAdapter ?? preparePortableDurableAdapter)(
|
|
36063
|
-
adapterId
|
|
37808
|
+
adapterId,
|
|
37809
|
+
config2
|
|
36064
37810
|
);
|
|
36065
37811
|
checks.push({
|
|
36066
37812
|
name: "provider_runtime",
|
|
@@ -36318,6 +38064,7 @@ Waiting for approval...
|
|
|
36318
38064
|
if (adapterId !== "codex") {
|
|
36319
38065
|
const prepared = await (dependencies.prepareDurableAdapter ?? preparePortableDurableAdapter)(
|
|
36320
38066
|
adapterId,
|
|
38067
|
+
config2,
|
|
36321
38068
|
cancellation.signal
|
|
36322
38069
|
);
|
|
36323
38070
|
const summary = await (dependencies.runPortableDurableAdapter ?? defaultRunPortableDurableAdapter)({
|
|
@@ -36417,7 +38164,27 @@ Waiting for approval...
|
|
|
36417
38164
|
}
|
|
36418
38165
|
return record2;
|
|
36419
38166
|
};
|
|
36420
|
-
|
|
38167
|
+
parseOptionalAgentStdin = async (dependencies, allowedKeys) => {
|
|
38168
|
+
if (!dependencies.readStdin && process.stdin.isTTY) return {};
|
|
38169
|
+
const raw = await (dependencies.readStdin ?? defaultReadStdin)();
|
|
38170
|
+
if (!raw.trim()) return {};
|
|
38171
|
+
let value;
|
|
38172
|
+
try {
|
|
38173
|
+
value = JSON.parse(raw);
|
|
38174
|
+
} catch {
|
|
38175
|
+
throw new Error("Agent-driven inference stdin must be one JSON object.");
|
|
38176
|
+
}
|
|
38177
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
38178
|
+
throw new Error("Agent-driven inference stdin must be one JSON object.");
|
|
38179
|
+
}
|
|
38180
|
+
const record2 = value;
|
|
38181
|
+
const unexpected = Object.keys(record2).filter((key) => !allowedKeys.includes(key));
|
|
38182
|
+
if (unexpected.length > 0) {
|
|
38183
|
+
throw new Error(`Unsupported agent-driven inference fields: ${unexpected.join(", ")}.`);
|
|
38184
|
+
}
|
|
38185
|
+
return record2;
|
|
38186
|
+
};
|
|
38187
|
+
agentOperationId = (kind) => `${kind}-${randomUUID5()}`;
|
|
36421
38188
|
agentSession = async (config2, dependencies, warnings, signal) => {
|
|
36422
38189
|
if (await readRevocationCheckpoint(config2)) {
|
|
36423
38190
|
throw new Error("Inference host revocation recovery must finish first.");
|
|
@@ -36461,11 +38228,419 @@ Waiting for approval...
|
|
|
36461
38228
|
reasoning_effort: result2.reasoning_effort,
|
|
36462
38229
|
lanes: ["main", "review", "screener"],
|
|
36463
38230
|
response_modes: ["provider_response", "decision_candidate"],
|
|
38231
|
+
control_modes: ["provider", "agent"],
|
|
36464
38232
|
execution_modes: ["client", "server"],
|
|
36465
38233
|
next_command: "vtx inference-host agent-next --wait-seconds 50 --json",
|
|
38234
|
+
agent_next_command: "vtx inference-host agent-assignment-next --wait-seconds 50 --json",
|
|
36466
38235
|
keeper_command: "vtx inference-host agent-run"
|
|
36467
38236
|
}, parsed.json),
|
|
36468
38237
|
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38238
|
+
` : ""
|
|
38239
|
+
};
|
|
38240
|
+
};
|
|
38241
|
+
foregroundAgentControlState = (hostId, updatedAt) => ({
|
|
38242
|
+
schema_version: "vtx_foreground_agent_control_v1",
|
|
38243
|
+
host_id: hostId,
|
|
38244
|
+
assignment: null,
|
|
38245
|
+
pending_next: null,
|
|
38246
|
+
pending_decision: null,
|
|
38247
|
+
next_wake_at: null,
|
|
38248
|
+
updated_at: updatedAt
|
|
38249
|
+
});
|
|
38250
|
+
requireForegroundAgentState = async (config2, hostId) => {
|
|
38251
|
+
const state = await readInferenceForegroundAgentControlState(config2.statePath);
|
|
38252
|
+
if (!state?.assignment) {
|
|
38253
|
+
throw new Error("No active foreground Agent assignment. Run agent-assignment-next first.");
|
|
38254
|
+
}
|
|
38255
|
+
if (state.host_id !== hostId) {
|
|
38256
|
+
throw new Error("Foreground Agent assignment belongs to another inference host.");
|
|
38257
|
+
}
|
|
38258
|
+
return state;
|
|
38259
|
+
};
|
|
38260
|
+
assignmentFromClaim = (result2) => ({
|
|
38261
|
+
assignment_id: result2.assignment_id,
|
|
38262
|
+
assignment_generation: result2.assignment_generation,
|
|
38263
|
+
model_id: result2.model_id,
|
|
38264
|
+
reasoning_effort: result2.reasoning_effort,
|
|
38265
|
+
bot_mode: result2.bot_mode,
|
|
38266
|
+
execution_mode: result2.execution_mode,
|
|
38267
|
+
allowed_symbols: result2.allowed_symbols,
|
|
38268
|
+
data_contract: result2.data_contract,
|
|
38269
|
+
output_schema: result2.output_schema,
|
|
38270
|
+
minimum_wake_seconds: result2.minimum_wake_seconds,
|
|
38271
|
+
maximum_wake_seconds: result2.maximum_wake_seconds,
|
|
38272
|
+
lease_expires_at: result2.lease_expires_at
|
|
38273
|
+
});
|
|
38274
|
+
foregroundAssignmentNext = async (config2, parsed, dependencies, warnings) => {
|
|
38275
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38276
|
+
const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
38277
|
+
const sleep4 = dependencies.sleep ?? (async (milliseconds) => {
|
|
38278
|
+
await new Promise((resolve6) => setTimeout(resolve6, milliseconds));
|
|
38279
|
+
});
|
|
38280
|
+
const stopAt = now().getTime() + parsed.waitSeconds * 1e3;
|
|
38281
|
+
let state = await readInferenceForegroundAgentControlState(config2.statePath) ?? foregroundAgentControlState(session.localState.host_id, now().toISOString());
|
|
38282
|
+
if (state.host_id !== session.localState.host_id) {
|
|
38283
|
+
throw new Error("Foreground Agent recovery state belongs to another inference host.");
|
|
38284
|
+
}
|
|
38285
|
+
if (state.pending_decision) {
|
|
38286
|
+
throw new Error("Resolve the pending Agent decision before claiming another assignment.");
|
|
38287
|
+
}
|
|
38288
|
+
while (true) {
|
|
38289
|
+
if (!state.pending_next) {
|
|
38290
|
+
const requestedAt = now().toISOString();
|
|
38291
|
+
state = {
|
|
38292
|
+
...state,
|
|
38293
|
+
pending_next: {
|
|
38294
|
+
operation_id: agentOperationId("agent-assignment-next"),
|
|
38295
|
+
requested_at: requestedAt
|
|
38296
|
+
},
|
|
38297
|
+
updated_at: requestedAt
|
|
38298
|
+
};
|
|
38299
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38300
|
+
}
|
|
38301
|
+
const pending = state.pending_next;
|
|
38302
|
+
let result2;
|
|
38303
|
+
try {
|
|
38304
|
+
result2 = await session.client.callTool("inference.agent.assignment.next", {
|
|
38305
|
+
operation_id: pending.operation_id,
|
|
38306
|
+
host_id: session.localState.host_id,
|
|
38307
|
+
requested_at: pending.requested_at,
|
|
38308
|
+
contract_version: "agent_assignment_v2",
|
|
38309
|
+
...state.assignment ? {
|
|
38310
|
+
assignment_id: state.assignment.assignment_id,
|
|
38311
|
+
assignment_generation: state.assignment.assignment_generation
|
|
38312
|
+
} : {}
|
|
38313
|
+
});
|
|
38314
|
+
} catch (error48) {
|
|
38315
|
+
if (error48 && typeof error48 === "object" && error48.definitivelyNotApplied === true) {
|
|
38316
|
+
state = { ...state, pending_next: null, updated_at: now().toISOString() };
|
|
38317
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38318
|
+
}
|
|
38319
|
+
throw error48;
|
|
38320
|
+
}
|
|
38321
|
+
if (result2.claim_state === "claimed") {
|
|
38322
|
+
const assignment = assignmentFromClaim(result2);
|
|
38323
|
+
state = {
|
|
38324
|
+
...state,
|
|
38325
|
+
assignment,
|
|
38326
|
+
pending_next: null,
|
|
38327
|
+
next_wake_at: null,
|
|
38328
|
+
updated_at: now().toISOString()
|
|
38329
|
+
};
|
|
38330
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38331
|
+
return {
|
|
38332
|
+
exitCode: 0,
|
|
38333
|
+
stdout: render({
|
|
38334
|
+
...result2,
|
|
38335
|
+
instructions: "VTX supplied no trading prompt or prepared context. Choose your own cadence; use agent-data-call zero or more times, submit the exact output_schema through agent-decision-submit, then record the next wake with agent-assignment-heartbeat. Keep agent-run open for liveness.",
|
|
38336
|
+
data_command: "vtx inference-host agent-data-call --json",
|
|
38337
|
+
decision_command: "vtx inference-host agent-decision-submit --json",
|
|
38338
|
+
decision_input: {
|
|
38339
|
+
candidate: "<object matching output_schema>",
|
|
38340
|
+
provenance: {
|
|
38341
|
+
source: "external_agent",
|
|
38342
|
+
agent_run_id: "<stable harness run id>",
|
|
38343
|
+
requested_model: result2.model_id,
|
|
38344
|
+
effective_model: "<actual model used>",
|
|
38345
|
+
requested_reasoning_effort: result2.reasoning_effort,
|
|
38346
|
+
effective_reasoning_effort: "<actual reasoning effort used>"
|
|
38347
|
+
}
|
|
38348
|
+
},
|
|
38349
|
+
heartbeat_command: "vtx inference-host agent-assignment-heartbeat --json",
|
|
38350
|
+
release_command: "vtx inference-host agent-assignment-release --json"
|
|
38351
|
+
}, parsed.json),
|
|
38352
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38353
|
+
` : ""
|
|
38354
|
+
};
|
|
38355
|
+
}
|
|
38356
|
+
state = { ...state, pending_next: null, updated_at: now().toISOString() };
|
|
38357
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38358
|
+
const remaining = stopAt - now().getTime();
|
|
38359
|
+
if (remaining <= 0 || parsed.waitSeconds === 0) {
|
|
38360
|
+
return {
|
|
38361
|
+
exitCode: 0,
|
|
38362
|
+
stdout: render(result2, parsed.json),
|
|
38363
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38364
|
+
` : ""
|
|
38365
|
+
};
|
|
38366
|
+
}
|
|
38367
|
+
await sleep4(Math.min(remaining, Math.max(50, result2.retry_after_ms)));
|
|
38368
|
+
}
|
|
38369
|
+
};
|
|
38370
|
+
foregroundAssignmentHeartbeat = async (config2, parsed, dependencies, warnings) => {
|
|
38371
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38372
|
+
const state = await requireForegroundAgentState(
|
|
38373
|
+
config2,
|
|
38374
|
+
session.localState.host_id
|
|
38375
|
+
);
|
|
38376
|
+
const input = await parseOptionalAgentStdin(dependencies, ["next_wake_at"]);
|
|
38377
|
+
const nextWakeAt = input.next_wake_at;
|
|
38378
|
+
if (nextWakeAt !== void 0 && (typeof nextWakeAt !== "string" || !Number.isFinite(Date.parse(nextWakeAt)))) {
|
|
38379
|
+
throw new Error("next_wake_at must be an ISO timestamp.");
|
|
38380
|
+
}
|
|
38381
|
+
const requestedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
38382
|
+
const result2 = await session.client.callTool("inference.agent.assignment.heartbeat", {
|
|
38383
|
+
operation_id: agentOperationId("agent-assignment-heartbeat"),
|
|
38384
|
+
host_id: session.localState.host_id,
|
|
38385
|
+
assignment_id: state.assignment.assignment_id,
|
|
38386
|
+
assignment_generation: state.assignment.assignment_generation,
|
|
38387
|
+
requested_at: requestedAt,
|
|
38388
|
+
...nextWakeAt === void 0 ? {} : { next_wake_at: nextWakeAt }
|
|
38389
|
+
});
|
|
38390
|
+
if (result2.directive === "cancel") {
|
|
38391
|
+
await handleForegroundCancelledAssignment(config2, session, state, requestedAt);
|
|
38392
|
+
} else {
|
|
38393
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38394
|
+
...state,
|
|
38395
|
+
assignment: { ...state.assignment, lease_expires_at: result2.lease_expires_at },
|
|
38396
|
+
next_wake_at: result2.next_wake_at ?? state.next_wake_at,
|
|
38397
|
+
updated_at: requestedAt
|
|
38398
|
+
});
|
|
38399
|
+
}
|
|
38400
|
+
return {
|
|
38401
|
+
exitCode: 0,
|
|
38402
|
+
stdout: render(result2, parsed.json),
|
|
38403
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38404
|
+
` : ""
|
|
38405
|
+
};
|
|
38406
|
+
};
|
|
38407
|
+
foregroundDataCall = async (config2, parsed, dependencies, warnings) => {
|
|
38408
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38409
|
+
const state = await requireForegroundAgentState(config2, session.localState.host_id);
|
|
38410
|
+
const input = await parseAgentStdin(dependencies, ["capability", "arguments"]);
|
|
38411
|
+
const capability = typeof input.capability === "string" ? input.capability.trim() : "";
|
|
38412
|
+
if (!capability || !state.assignment.data_contract.some((item) => item.id === capability)) {
|
|
38413
|
+
throw new Error("Agent data capability is not allowed by the current assignment.");
|
|
38414
|
+
}
|
|
38415
|
+
if (!input.arguments || typeof input.arguments !== "object" || Array.isArray(input.arguments)) {
|
|
38416
|
+
throw new Error("Agent data arguments must be one JSON object.");
|
|
38417
|
+
}
|
|
38418
|
+
const result2 = await session.client.callTool("inference.agent.data.call", {
|
|
38419
|
+
operation_id: agentOperationId("agent-data-call"),
|
|
38420
|
+
host_id: session.localState.host_id,
|
|
38421
|
+
assignment_id: state.assignment.assignment_id,
|
|
38422
|
+
assignment_generation: state.assignment.assignment_generation,
|
|
38423
|
+
capability,
|
|
38424
|
+
arguments: input.arguments,
|
|
38425
|
+
requested_at: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
38426
|
+
});
|
|
38427
|
+
return {
|
|
38428
|
+
exitCode: 0,
|
|
38429
|
+
stdout: render(result2, parsed.json),
|
|
38430
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38431
|
+
` : ""
|
|
38432
|
+
};
|
|
38433
|
+
};
|
|
38434
|
+
foregroundDecisionStatusRequest = (hostId, state) => ({
|
|
38435
|
+
operation_id: state.pending_decision.request.operation_id,
|
|
38436
|
+
host_id: hostId,
|
|
38437
|
+
assignment_id: state.assignment.assignment_id,
|
|
38438
|
+
assignment_generation: state.assignment.assignment_generation
|
|
38439
|
+
});
|
|
38440
|
+
foregroundAssignmentLeaseEnded = (state, now) => Boolean(state.assignment) && Date.parse(state.assignment.lease_expires_at) <= now.getTime();
|
|
38441
|
+
handleForegroundCancelledAssignment = async (config2, session, state, requestedAt, signal) => {
|
|
38442
|
+
if (!state.pending_decision) {
|
|
38443
|
+
await clearInferenceForegroundAgentControlState(config2.statePath);
|
|
38444
|
+
return;
|
|
38445
|
+
}
|
|
38446
|
+
const cancelledState = {
|
|
38447
|
+
...state,
|
|
38448
|
+
assignment: {
|
|
38449
|
+
...state.assignment,
|
|
38450
|
+
lease_expires_at: requestedAt
|
|
38451
|
+
},
|
|
38452
|
+
pending_decision: {
|
|
38453
|
+
...state.pending_decision,
|
|
38454
|
+
last_status_check_at: requestedAt
|
|
38455
|
+
},
|
|
38456
|
+
next_wake_at: null,
|
|
38457
|
+
updated_at: requestedAt
|
|
38458
|
+
};
|
|
38459
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, cancelledState);
|
|
38460
|
+
try {
|
|
38461
|
+
await session.client.callTool(
|
|
38462
|
+
"inference.agent.decision.status",
|
|
38463
|
+
foregroundDecisionStatusRequest(session.localState.host_id, cancelledState),
|
|
38464
|
+
{ signal }
|
|
38465
|
+
);
|
|
38466
|
+
} catch {
|
|
38467
|
+
return;
|
|
38468
|
+
}
|
|
38469
|
+
await clearInferenceForegroundAgentControlState(config2.statePath);
|
|
38470
|
+
};
|
|
38471
|
+
foregroundDecisionStatus = async (config2, parsed, dependencies, warnings) => {
|
|
38472
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38473
|
+
let state = await requireForegroundAgentState(config2, session.localState.host_id);
|
|
38474
|
+
if (!state.pending_decision) {
|
|
38475
|
+
throw new Error("No uncertain foreground Agent decision requires status recovery.");
|
|
38476
|
+
}
|
|
38477
|
+
const checkedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
38478
|
+
state = {
|
|
38479
|
+
...state,
|
|
38480
|
+
pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
|
|
38481
|
+
updated_at: checkedAt
|
|
38482
|
+
};
|
|
38483
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38484
|
+
const result2 = await session.client.callTool(
|
|
38485
|
+
"inference.agent.decision.status",
|
|
38486
|
+
foregroundDecisionStatusRequest(session.localState.host_id, state)
|
|
38487
|
+
);
|
|
38488
|
+
const assignmentLeaseEnded = foregroundAssignmentLeaseEnded(state, new Date(checkedAt));
|
|
38489
|
+
if (result2.found || assignmentLeaseEnded) {
|
|
38490
|
+
if (assignmentLeaseEnded) {
|
|
38491
|
+
await clearInferenceForegroundAgentControlState(config2.statePath);
|
|
38492
|
+
} else {
|
|
38493
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38494
|
+
...state,
|
|
38495
|
+
pending_decision: null,
|
|
38496
|
+
updated_at: checkedAt
|
|
38497
|
+
});
|
|
38498
|
+
}
|
|
38499
|
+
}
|
|
38500
|
+
return {
|
|
38501
|
+
exitCode: 0,
|
|
38502
|
+
stdout: render(result2, parsed.json),
|
|
38503
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38504
|
+
` : ""
|
|
38505
|
+
};
|
|
38506
|
+
};
|
|
38507
|
+
foregroundDecisionSubmit = async (config2, parsed, dependencies, warnings) => {
|
|
38508
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38509
|
+
const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
|
|
38510
|
+
let state = await requireForegroundAgentState(config2, session.localState.host_id);
|
|
38511
|
+
if (!state.pending_decision) {
|
|
38512
|
+
const input = await parseAgentStdin(dependencies, ["candidate", "provenance"]);
|
|
38513
|
+
if (!input.candidate || typeof input.candidate !== "object" || Array.isArray(input.candidate)) {
|
|
38514
|
+
throw new Error("Agent decision candidate must be one JSON object.");
|
|
38515
|
+
}
|
|
38516
|
+
if (!input.provenance || typeof input.provenance !== "object" || Array.isArray(input.provenance)) {
|
|
38517
|
+
throw new Error("Agent decision provenance must be one JSON object.");
|
|
38518
|
+
}
|
|
38519
|
+
const observedAt = now().toISOString();
|
|
38520
|
+
state = {
|
|
38521
|
+
...state,
|
|
38522
|
+
pending_decision: {
|
|
38523
|
+
request: {
|
|
38524
|
+
assignment_id: state.assignment.assignment_id,
|
|
38525
|
+
assignment_generation: state.assignment.assignment_generation,
|
|
38526
|
+
operation_id: agentOperationId("agent-decision-submit"),
|
|
38527
|
+
candidate: input.candidate,
|
|
38528
|
+
observed_at: observedAt,
|
|
38529
|
+
provenance: input.provenance
|
|
38530
|
+
},
|
|
38531
|
+
first_transmit_at: null,
|
|
38532
|
+
last_status_check_at: null
|
|
38533
|
+
},
|
|
38534
|
+
updated_at: observedAt
|
|
38535
|
+
};
|
|
38536
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38537
|
+
} else {
|
|
38538
|
+
const checkedAt = now().toISOString();
|
|
38539
|
+
state = {
|
|
38540
|
+
...state,
|
|
38541
|
+
pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
|
|
38542
|
+
updated_at: checkedAt
|
|
38543
|
+
};
|
|
38544
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38545
|
+
const status = await session.client.callTool(
|
|
38546
|
+
"inference.agent.decision.status",
|
|
38547
|
+
foregroundDecisionStatusRequest(session.localState.host_id, state)
|
|
38548
|
+
);
|
|
38549
|
+
if (status.found) {
|
|
38550
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38551
|
+
...state,
|
|
38552
|
+
pending_decision: null,
|
|
38553
|
+
updated_at: checkedAt
|
|
38554
|
+
});
|
|
38555
|
+
return {
|
|
38556
|
+
exitCode: 0,
|
|
38557
|
+
stdout: render({ ...status, recovered: true }, parsed.json),
|
|
38558
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38559
|
+
` : ""
|
|
38560
|
+
};
|
|
38561
|
+
}
|
|
38562
|
+
}
|
|
38563
|
+
const transmittedAt = now().toISOString();
|
|
38564
|
+
state = {
|
|
38565
|
+
...state,
|
|
38566
|
+
pending_decision: {
|
|
38567
|
+
...state.pending_decision,
|
|
38568
|
+
first_transmit_at: state.pending_decision.first_transmit_at ?? transmittedAt
|
|
38569
|
+
},
|
|
38570
|
+
updated_at: transmittedAt
|
|
38571
|
+
};
|
|
38572
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38573
|
+
try {
|
|
38574
|
+
const result2 = await session.client.callTool(
|
|
38575
|
+
"inference.agent.decision.submit",
|
|
38576
|
+
state.pending_decision.request
|
|
38577
|
+
);
|
|
38578
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38579
|
+
...state,
|
|
38580
|
+
pending_decision: null,
|
|
38581
|
+
updated_at: now().toISOString()
|
|
38582
|
+
});
|
|
38583
|
+
return {
|
|
38584
|
+
exitCode: 0,
|
|
38585
|
+
stdout: render(result2, parsed.json),
|
|
38586
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38587
|
+
` : ""
|
|
38588
|
+
};
|
|
38589
|
+
} catch (error48) {
|
|
38590
|
+
const checkedAt = now().toISOString();
|
|
38591
|
+
state = {
|
|
38592
|
+
...state,
|
|
38593
|
+
pending_decision: { ...state.pending_decision, last_status_check_at: checkedAt },
|
|
38594
|
+
updated_at: checkedAt
|
|
38595
|
+
};
|
|
38596
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, state);
|
|
38597
|
+
try {
|
|
38598
|
+
const status = await session.client.callTool(
|
|
38599
|
+
"inference.agent.decision.status",
|
|
38600
|
+
foregroundDecisionStatusRequest(session.localState.host_id, state)
|
|
38601
|
+
);
|
|
38602
|
+
if (status.found) {
|
|
38603
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38604
|
+
...state,
|
|
38605
|
+
pending_decision: null,
|
|
38606
|
+
updated_at: checkedAt
|
|
38607
|
+
});
|
|
38608
|
+
return {
|
|
38609
|
+
exitCode: 0,
|
|
38610
|
+
stdout: render({ ...status, recovered: true }, parsed.json),
|
|
38611
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
38612
|
+
` : ""
|
|
38613
|
+
};
|
|
38614
|
+
}
|
|
38615
|
+
} catch {
|
|
38616
|
+
}
|
|
38617
|
+
throw error48;
|
|
38618
|
+
}
|
|
38619
|
+
};
|
|
38620
|
+
foregroundAssignmentRelease = async (config2, parsed, dependencies, warnings) => {
|
|
38621
|
+
const session = await agentSession(config2, dependencies, warnings);
|
|
38622
|
+
const state = await requireForegroundAgentState(config2, session.localState.host_id);
|
|
38623
|
+
if (state.pending_decision) {
|
|
38624
|
+
throw new Error("Resolve the pending Agent decision before releasing its assignment.");
|
|
38625
|
+
}
|
|
38626
|
+
const input = await parseOptionalAgentStdin(dependencies, ["reason_code"]);
|
|
38627
|
+
const reasonCode = input.reason_code === void 0 ? "agent_released" : input.reason_code;
|
|
38628
|
+
if (typeof reasonCode !== "string" || !/^[a-z0-9][a-z0-9._-]{0,95}$/u.test(reasonCode)) {
|
|
38629
|
+
throw new Error("reason_code must be a safe lowercase code.");
|
|
38630
|
+
}
|
|
38631
|
+
const result2 = await session.client.callTool("inference.agent.assignment.release", {
|
|
38632
|
+
operation_id: agentOperationId("agent-assignment-release"),
|
|
38633
|
+
host_id: session.localState.host_id,
|
|
38634
|
+
assignment_id: state.assignment.assignment_id,
|
|
38635
|
+
assignment_generation: state.assignment.assignment_generation,
|
|
38636
|
+
reason_code: reasonCode,
|
|
38637
|
+
requested_at: (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString()
|
|
38638
|
+
});
|
|
38639
|
+
await clearInferenceForegroundAgentControlState(config2.statePath);
|
|
38640
|
+
return {
|
|
38641
|
+
exitCode: 0,
|
|
38642
|
+
stdout: render(result2, parsed.json),
|
|
38643
|
+
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
36469
38644
|
` : ""
|
|
36470
38645
|
};
|
|
36471
38646
|
};
|
|
@@ -36473,6 +38648,7 @@ Waiting for approval...
|
|
|
36473
38648
|
const cancellation = lifecycleCancellation(dependencies);
|
|
36474
38649
|
let keeperLock = null;
|
|
36475
38650
|
let heartbeatCount = 0;
|
|
38651
|
+
let assignmentHeartbeatCount = 0;
|
|
36476
38652
|
try {
|
|
36477
38653
|
keeperLock = await acquireInferenceHostProcessLock(foregroundHostLockPath(config2));
|
|
36478
38654
|
const store = configuredCredentialStore(config2, dependencies, (message) => {
|
|
@@ -36506,6 +38682,7 @@ Waiting for approval...
|
|
|
36506
38682
|
}
|
|
36507
38683
|
if (commandLock) {
|
|
36508
38684
|
let heartbeatSuppressed = false;
|
|
38685
|
+
let assignmentHeartbeatComplete = true;
|
|
36509
38686
|
try {
|
|
36510
38687
|
const active = await readInferenceAgentAttemptState(config2.statePath);
|
|
36511
38688
|
const pendingNext = await readInferenceAgentNextState(config2.statePath);
|
|
@@ -36565,10 +38742,65 @@ Waiting for approval...
|
|
|
36565
38742
|
}
|
|
36566
38743
|
}
|
|
36567
38744
|
}
|
|
38745
|
+
const control = await readInferenceForegroundAgentControlState(config2.statePath);
|
|
38746
|
+
if (control && control.host_id !== session.localState.host_id) {
|
|
38747
|
+
throw new Error("Foreground Agent control state belongs to another inference host.");
|
|
38748
|
+
}
|
|
38749
|
+
if (control?.assignment) {
|
|
38750
|
+
assignmentHeartbeatComplete = false;
|
|
38751
|
+
try {
|
|
38752
|
+
const requestedAt = (dependencies.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
38753
|
+
const result2 = await session.client.callTool(
|
|
38754
|
+
"inference.agent.assignment.heartbeat",
|
|
38755
|
+
{
|
|
38756
|
+
operation_id: agentOperationId("agent-assignment-heartbeat"),
|
|
38757
|
+
host_id: session.localState.host_id,
|
|
38758
|
+
assignment_id: control.assignment.assignment_id,
|
|
38759
|
+
assignment_generation: control.assignment.assignment_generation,
|
|
38760
|
+
requested_at: requestedAt
|
|
38761
|
+
},
|
|
38762
|
+
{ signal: cancellation.signal }
|
|
38763
|
+
);
|
|
38764
|
+
assignmentHeartbeatComplete = true;
|
|
38765
|
+
assignmentHeartbeatCount += 1;
|
|
38766
|
+
if (result2.directive === "cancel") {
|
|
38767
|
+
await handleForegroundCancelledAssignment(
|
|
38768
|
+
config2,
|
|
38769
|
+
session,
|
|
38770
|
+
control,
|
|
38771
|
+
requestedAt,
|
|
38772
|
+
cancellation.signal
|
|
38773
|
+
);
|
|
38774
|
+
} else {
|
|
38775
|
+
await writeInferenceForegroundAgentControlState(config2.statePath, {
|
|
38776
|
+
...control,
|
|
38777
|
+
assignment: {
|
|
38778
|
+
...control.assignment,
|
|
38779
|
+
lease_expires_at: result2.lease_expires_at
|
|
38780
|
+
},
|
|
38781
|
+
updated_at: requestedAt
|
|
38782
|
+
});
|
|
38783
|
+
}
|
|
38784
|
+
} catch (error48) {
|
|
38785
|
+
if (cancellation.signal.aborted) break;
|
|
38786
|
+
if (!retryableAgentHeartbeatError(error48)) throw error48;
|
|
38787
|
+
consecutiveHeartbeatFailures += 1;
|
|
38788
|
+
retryDelayMs = Math.min(
|
|
38789
|
+
AGENT_HEARTBEAT_INTERVAL_MS * 2 ** Math.max(0, consecutiveHeartbeatFailures - 1),
|
|
38790
|
+
AGENT_HEARTBEAT_MAX_RETRY_DELAY_MS
|
|
38791
|
+
);
|
|
38792
|
+
emitStderr(parsed.json ? `${JSON.stringify({
|
|
38793
|
+
status: "assignment_heartbeat_retry",
|
|
38794
|
+
retry_after_ms: retryDelayMs
|
|
38795
|
+
})}
|
|
38796
|
+
` : `Foreground Agent assignment heartbeat was temporarily unavailable; retrying in ${retryDelayMs}ms.
|
|
38797
|
+
`);
|
|
38798
|
+
}
|
|
38799
|
+
}
|
|
36568
38800
|
} finally {
|
|
36569
38801
|
await commandLock.release();
|
|
36570
38802
|
}
|
|
36571
|
-
if (parsed.once && (heartbeatCount > 0 || heartbeatSuppressed)) break;
|
|
38803
|
+
if (parsed.once && (heartbeatCount > 0 || heartbeatSuppressed) && assignmentHeartbeatComplete) break;
|
|
36572
38804
|
}
|
|
36573
38805
|
if (parsed.once && !commandLock) break;
|
|
36574
38806
|
await (dependencies.sleep ?? (async (milliseconds) => {
|
|
@@ -36577,7 +38809,11 @@ Waiting for approval...
|
|
|
36577
38809
|
}
|
|
36578
38810
|
return {
|
|
36579
38811
|
exitCode: 0,
|
|
36580
|
-
stdout: render({
|
|
38812
|
+
stdout: render({
|
|
38813
|
+
status: "stopped",
|
|
38814
|
+
heartbeats: heartbeatCount,
|
|
38815
|
+
assignment_heartbeats: assignmentHeartbeatCount
|
|
38816
|
+
}, parsed.json),
|
|
36581
38817
|
stderr: warnings.length > 0 ? `${warnings.join("\n")}
|
|
36582
38818
|
` : ""
|
|
36583
38819
|
};
|
|
@@ -36965,7 +39201,7 @@ Waiting for approval...
|
|
|
36965
39201
|
if (recoveryRaw === null && existingTransaction?.phase !== "reconciled") {
|
|
36966
39202
|
throw new Error("Codex recovery evidence changed before service recovery began.");
|
|
36967
39203
|
}
|
|
36968
|
-
const transactionId = existingTransaction?.transaction_id ??
|
|
39204
|
+
const transactionId = existingTransaction?.transaction_id ?? randomUUID5();
|
|
36969
39205
|
const backupPath = existingTransaction?.recovery_backup_path ?? recoveryBackupPath(config2, transactionId);
|
|
36970
39206
|
if (!existingTransaction) {
|
|
36971
39207
|
await writeAtomicInferencePrivateFile(backupPath, recoveryRaw);
|
|
@@ -36974,7 +39210,7 @@ Waiting for approval...
|
|
|
36974
39210
|
backupPath,
|
|
36975
39211
|
"Codex service recovery backup"
|
|
36976
39212
|
);
|
|
36977
|
-
const backupSha256 = backupRaw === null ? null :
|
|
39213
|
+
const backupSha256 = backupRaw === null ? null : createHash8("sha256").update(backupRaw).digest("hex");
|
|
36978
39214
|
if (backupSha256 === null || existingTransaction && backupSha256 !== existingTransaction.recovery_backup_sha256) {
|
|
36979
39215
|
throw new Error("Codex service recovery backup is missing or changed.");
|
|
36980
39216
|
}
|
|
@@ -36985,7 +39221,7 @@ Waiting for approval...
|
|
|
36985
39221
|
existingTransaction?.cleanup_confirmed_attempt_ids ?? [],
|
|
36986
39222
|
existingTransaction?.phase ?? "prepared"
|
|
36987
39223
|
);
|
|
36988
|
-
const recoverySha256 = recoveryRaw === null ? null :
|
|
39224
|
+
const recoverySha256 = recoveryRaw === null ? null : createHash8("sha256").update(recoveryRaw).digest("hex");
|
|
36989
39225
|
const unresolvedAttemptIds = Object.keys(backupAttempts).filter((attemptId) => !existingTransaction?.cleanup_confirmed_attempt_ids.includes(attemptId) && !initialAttempts[attemptId]?.cleanupConfirmed);
|
|
36990
39226
|
const binary = unresolvedAttemptIds.length > 0 ? await (dependencies.resolveBinary ?? resolvePinnedCodexBinary)(env) : null;
|
|
36991
39227
|
let activeTransaction = existingTransaction;
|
|
@@ -37024,7 +39260,7 @@ Waiting for approval...
|
|
|
37024
39260
|
codexRecoveryPath(config2),
|
|
37025
39261
|
"Codex attempt recovery file"
|
|
37026
39262
|
);
|
|
37027
|
-
if (currentRaw === null || recoverySha256 === null ||
|
|
39263
|
+
if (currentRaw === null || recoverySha256 === null || createHash8("sha256").update(currentRaw).digest("hex") !== recoverySha256) {
|
|
37028
39264
|
throw new Error("Codex recovery evidence changed while the service was stopping.");
|
|
37029
39265
|
}
|
|
37030
39266
|
const proof = await (dependencies.proveCodexQuiescence ?? proveCodexSameBootQuiescence)({
|
|
@@ -37113,7 +39349,7 @@ Waiting for approval...
|
|
|
37113
39349
|
serviceRecoveryTransactionPath(config2),
|
|
37114
39350
|
"Inference-host service recovery transaction"
|
|
37115
39351
|
);
|
|
37116
|
-
await
|
|
39352
|
+
await rm7(backupPath, { force: true });
|
|
37117
39353
|
}
|
|
37118
39354
|
}
|
|
37119
39355
|
} finally {
|
|
@@ -37194,7 +39430,8 @@ Waiting for approval...
|
|
|
37194
39430
|
const displayName = resolveDurableServiceDisplayName(parsed, dependencies);
|
|
37195
39431
|
if (adapter !== "codex") {
|
|
37196
39432
|
const prepared = await (dependencies.prepareDurableAdapter ?? preparePortableDurableAdapter)(
|
|
37197
|
-
adapter
|
|
39433
|
+
adapter,
|
|
39434
|
+
config2
|
|
37198
39435
|
);
|
|
37199
39436
|
try {
|
|
37200
39437
|
const status2 = await manager.install({
|
|
@@ -37381,11 +39618,11 @@ Waiting for approval...
|
|
|
37381
39618
|
});
|
|
37382
39619
|
|
|
37383
39620
|
// lib/agent-core/config.ts
|
|
37384
|
-
import { mkdir as mkdir5, readFile as readFile6, rm as
|
|
37385
|
-
import { dirname as
|
|
39621
|
+
import { mkdir as mkdir5, readFile as readFile6, rm as rm8, writeFile as writeFile3 } from "node:fs/promises";
|
|
39622
|
+
import { dirname as dirname6, join as join9 } from "node:path";
|
|
37386
39623
|
import { homedir as homedir3 } from "node:os";
|
|
37387
39624
|
function defaultBaseDir() {
|
|
37388
|
-
return
|
|
39625
|
+
return join9(homedir3(), ".vtx");
|
|
37389
39626
|
}
|
|
37390
39627
|
function resolveAgentCliConfig(env = process.env) {
|
|
37391
39628
|
const baseDir = String(env.VTX_HOME || "").trim() || defaultBaseDir();
|
|
@@ -37393,8 +39630,8 @@ function resolveAgentCliConfig(env = process.env) {
|
|
|
37393
39630
|
const parsedProfile = rawProfile ? Number(rawProfile) : NaN;
|
|
37394
39631
|
return {
|
|
37395
39632
|
apiUrl: String(env.VTX_API_URL || "http://localhost:8000").replace(/\/+$/, ""),
|
|
37396
|
-
tokenPath: String(env.VTX_TOKEN_PATH || "").trim() ||
|
|
37397
|
-
statePath: String(env.VTX_RUNTIME_STATE_PATH || "").trim() ||
|
|
39633
|
+
tokenPath: String(env.VTX_TOKEN_PATH || "").trim() || join9(baseDir, "token.json"),
|
|
39634
|
+
statePath: String(env.VTX_RUNTIME_STATE_PATH || "").trim() || join9(baseDir, "runtime-state.json"),
|
|
37398
39635
|
runtimeDeviceId: String(env.VTX_RUNTIME_DEVICE_ID || "").trim() || null,
|
|
37399
39636
|
activeProfileId: Number.isFinite(parsedProfile) && parsedProfile > 0 ? parsedProfile : null,
|
|
37400
39637
|
outputJson: String(env.VTX_OUTPUT || "").trim().toLowerCase() === "json"
|
|
@@ -37420,12 +39657,12 @@ async function readStoredAgentAuth(path) {
|
|
|
37420
39657
|
}
|
|
37421
39658
|
}
|
|
37422
39659
|
async function writeStoredAgentAuth(path, auth) {
|
|
37423
|
-
await mkdir5(
|
|
39660
|
+
await mkdir5(dirname6(path), { recursive: true });
|
|
37424
39661
|
await writeFile3(path, `${JSON.stringify(auth, null, 2)}
|
|
37425
39662
|
`, { encoding: "utf8", mode: 384 });
|
|
37426
39663
|
}
|
|
37427
39664
|
async function clearStoredAgentAuth(path) {
|
|
37428
|
-
await
|
|
39665
|
+
await rm8(path, { force: true });
|
|
37429
39666
|
}
|
|
37430
39667
|
async function readRuntimeState(path) {
|
|
37431
39668
|
try {
|
|
@@ -37455,12 +39692,12 @@ async function readRuntimeState(path) {
|
|
|
37455
39692
|
}
|
|
37456
39693
|
}
|
|
37457
39694
|
async function writeRuntimeState(path, state) {
|
|
37458
|
-
await mkdir5(
|
|
39695
|
+
await mkdir5(dirname6(path), { recursive: true });
|
|
37459
39696
|
await writeFile3(path, `${JSON.stringify(state, null, 2)}
|
|
37460
39697
|
`, { encoding: "utf8", mode: 384 });
|
|
37461
39698
|
}
|
|
37462
39699
|
async function clearRuntimeState(path) {
|
|
37463
|
-
await
|
|
39700
|
+
await rm8(path, { force: true });
|
|
37464
39701
|
}
|
|
37465
39702
|
var init_config2 = __esm({
|
|
37466
39703
|
"lib/agent-core/config.ts"() {
|
|
@@ -37486,7 +39723,7 @@ var init_types = __esm({
|
|
|
37486
39723
|
});
|
|
37487
39724
|
|
|
37488
39725
|
// lib/agent-core/client.ts
|
|
37489
|
-
import { randomUUID as
|
|
39726
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
37490
39727
|
function normalizeApiUrl(value) {
|
|
37491
39728
|
const parsed = String(value || "").trim();
|
|
37492
39729
|
if (!parsed) {
|
|
@@ -37748,7 +39985,7 @@ var init_client = __esm({
|
|
|
37748
39985
|
return this.request("/trading/ai/runtime/decision", {
|
|
37749
39986
|
method: "POST",
|
|
37750
39987
|
profileId,
|
|
37751
|
-
idempotencyKey:
|
|
39988
|
+
idempotencyKey: randomUUID6(),
|
|
37752
39989
|
headers: { "x-client-runtime-lease": leaseToken },
|
|
37753
39990
|
body: payload
|
|
37754
39991
|
});
|
|
@@ -37757,7 +39994,7 @@ var init_client = __esm({
|
|
|
37757
39994
|
return this.request("/trading/ai/runtime/trade-sync", {
|
|
37758
39995
|
method: "POST",
|
|
37759
39996
|
profileId,
|
|
37760
|
-
idempotencyKey:
|
|
39997
|
+
idempotencyKey: randomUUID6(),
|
|
37761
39998
|
headers: { "x-client-runtime-lease": leaseToken },
|
|
37762
39999
|
body: payload
|
|
37763
40000
|
});
|
|
@@ -37766,7 +40003,7 @@ var init_client = __esm({
|
|
|
37766
40003
|
return this.request("/trading/ai/runtime/error", {
|
|
37767
40004
|
method: "POST",
|
|
37768
40005
|
profileId,
|
|
37769
|
-
idempotencyKey:
|
|
40006
|
+
idempotencyKey: randomUUID6(),
|
|
37770
40007
|
headers: { "x-client-runtime-lease": leaseToken },
|
|
37771
40008
|
body: payload
|
|
37772
40009
|
});
|
|
@@ -37778,7 +40015,7 @@ var init_client = __esm({
|
|
|
37778
40015
|
return this.request("/trading/market-order", {
|
|
37779
40016
|
method: "POST",
|
|
37780
40017
|
profileId,
|
|
37781
|
-
idempotencyKey:
|
|
40018
|
+
idempotencyKey: randomUUID6(),
|
|
37782
40019
|
body: payload
|
|
37783
40020
|
});
|
|
37784
40021
|
}
|
|
@@ -37786,7 +40023,7 @@ var init_client = __esm({
|
|
|
37786
40023
|
return this.request("/trading/limit-order", {
|
|
37787
40024
|
method: "POST",
|
|
37788
40025
|
profileId,
|
|
37789
|
-
idempotencyKey:
|
|
40026
|
+
idempotencyKey: randomUUID6(),
|
|
37790
40027
|
body: payload
|
|
37791
40028
|
});
|
|
37792
40029
|
}
|
|
@@ -37794,7 +40031,7 @@ var init_client = __esm({
|
|
|
37794
40031
|
return this.request("/trading/cancel-order", {
|
|
37795
40032
|
method: "POST",
|
|
37796
40033
|
profileId,
|
|
37797
|
-
idempotencyKey:
|
|
40034
|
+
idempotencyKey: randomUUID6(),
|
|
37798
40035
|
body: payload
|
|
37799
40036
|
});
|
|
37800
40037
|
}
|
|
@@ -37813,7 +40050,7 @@ var init_client = __esm({
|
|
|
37813
40050
|
return this.request("/trading/ai/start", {
|
|
37814
40051
|
method: "POST",
|
|
37815
40052
|
profileId,
|
|
37816
|
-
idempotencyKey:
|
|
40053
|
+
idempotencyKey: randomUUID6(),
|
|
37817
40054
|
body: payload
|
|
37818
40055
|
});
|
|
37819
40056
|
}
|
|
@@ -37821,7 +40058,7 @@ var init_client = __esm({
|
|
|
37821
40058
|
return this.request("/trading/ai/stop", {
|
|
37822
40059
|
method: "POST",
|
|
37823
40060
|
profileId,
|
|
37824
|
-
idempotencyKey:
|
|
40061
|
+
idempotencyKey: randomUUID6(),
|
|
37825
40062
|
body: {}
|
|
37826
40063
|
});
|
|
37827
40064
|
}
|
|
@@ -37829,7 +40066,7 @@ var init_client = __esm({
|
|
|
37829
40066
|
return this.request("/trading/ai/assistant/start", {
|
|
37830
40067
|
method: "POST",
|
|
37831
40068
|
profileId,
|
|
37832
|
-
idempotencyKey:
|
|
40069
|
+
idempotencyKey: randomUUID6(),
|
|
37833
40070
|
body: {}
|
|
37834
40071
|
});
|
|
37835
40072
|
}
|
|
@@ -37837,7 +40074,7 @@ var init_client = __esm({
|
|
|
37837
40074
|
return this.request("/trading/ai/assistant/stop", {
|
|
37838
40075
|
method: "POST",
|
|
37839
40076
|
profileId,
|
|
37840
|
-
idempotencyKey:
|
|
40077
|
+
idempotencyKey: randomUUID6(),
|
|
37841
40078
|
body: {}
|
|
37842
40079
|
});
|
|
37843
40080
|
}
|
|
@@ -37845,7 +40082,7 @@ var init_client = __esm({
|
|
|
37845
40082
|
return this.request("/trading/ai/runtime/session/start", {
|
|
37846
40083
|
method: "POST",
|
|
37847
40084
|
profileId,
|
|
37848
|
-
idempotencyKey:
|
|
40085
|
+
idempotencyKey: randomUUID6(),
|
|
37849
40086
|
body: payload
|
|
37850
40087
|
});
|
|
37851
40088
|
}
|
|
@@ -37856,7 +40093,7 @@ var init_client = __esm({
|
|
|
37856
40093
|
return this.request("/trading/ai/runtime/session/stop", {
|
|
37857
40094
|
method: "POST",
|
|
37858
40095
|
profileId,
|
|
37859
|
-
idempotencyKey:
|
|
40096
|
+
idempotencyKey: randomUUID6(),
|
|
37860
40097
|
body: payload
|
|
37861
40098
|
});
|
|
37862
40099
|
}
|
|
@@ -37873,7 +40110,7 @@ var init_client = __esm({
|
|
|
37873
40110
|
}).request("/trading/ai/runtime/session/stop", {
|
|
37874
40111
|
method: "POST",
|
|
37875
40112
|
profileId,
|
|
37876
|
-
idempotencyKey:
|
|
40113
|
+
idempotencyKey: randomUUID6(),
|
|
37877
40114
|
body: payload
|
|
37878
40115
|
});
|
|
37879
40116
|
}
|
|
@@ -37890,8 +40127,8 @@ import {
|
|
|
37890
40127
|
unlinkSync,
|
|
37891
40128
|
writeFileSync
|
|
37892
40129
|
} from "node:fs";
|
|
37893
|
-
import { randomUUID as
|
|
37894
|
-
import { dirname as
|
|
40130
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
40131
|
+
import { dirname as dirname7 } from "node:path";
|
|
37895
40132
|
var parseStoredValues, FileBackedProtectionStorage, clientRuntimeProtectionStatePath;
|
|
37896
40133
|
var init_protection_storage = __esm({
|
|
37897
40134
|
"lib/agent-core/protection-storage.ts"() {
|
|
@@ -37944,10 +40181,10 @@ var init_protection_storage = __esm({
|
|
|
37944
40181
|
}
|
|
37945
40182
|
}
|
|
37946
40183
|
writeValues(values) {
|
|
37947
|
-
mkdirSync(
|
|
40184
|
+
mkdirSync(dirname7(this.path), { recursive: true, mode: 448 });
|
|
37948
40185
|
const serialized = `${JSON.stringify(values)}
|
|
37949
40186
|
`;
|
|
37950
|
-
const temporaryPath = `${this.path}.${process.pid}.${
|
|
40187
|
+
const temporaryPath = `${this.path}.${process.pid}.${randomUUID7()}.tmp`;
|
|
37951
40188
|
try {
|
|
37952
40189
|
writeFileSync(temporaryPath, serialized, {
|
|
37953
40190
|
encoding: "utf8",
|
|
@@ -37974,7 +40211,7 @@ var init_protection_storage = __esm({
|
|
|
37974
40211
|
});
|
|
37975
40212
|
|
|
37976
40213
|
// lib/agent-core/headless-runtime.ts
|
|
37977
|
-
import { randomUUID as
|
|
40214
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
37978
40215
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
37979
40216
|
function objectOrNull2(value) {
|
|
37980
40217
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
@@ -38072,8 +40309,8 @@ async function runAndReportLocalWorkCycle(options, state, leaseToken, context) {
|
|
|
38072
40309
|
return Boolean(result2.decision || tradeSync || result2.afterDecision);
|
|
38073
40310
|
}
|
|
38074
40311
|
async function startHeadlessRuntime(options) {
|
|
38075
|
-
const runtimeSessionId =
|
|
38076
|
-
const deviceId = String(options.deviceId || "").trim() ||
|
|
40312
|
+
const runtimeSessionId = randomUUID8();
|
|
40313
|
+
const deviceId = String(options.deviceId || "").trim() || randomUUID8();
|
|
38077
40314
|
const startResponse = await options.client.startRuntime(options.profileId, {
|
|
38078
40315
|
session_id: runtimeSessionId,
|
|
38079
40316
|
device_id: deviceId,
|
|
@@ -42758,8 +44995,8 @@ var init_rlp_encode = __esm({
|
|
|
42758
44995
|
});
|
|
42759
44996
|
|
|
42760
44997
|
// node_modules/ethers/lib.esm/utils/uuid.js
|
|
42761
|
-
function uuidV4(
|
|
42762
|
-
const bytes3 = getBytes(
|
|
44998
|
+
function uuidV4(randomBytes9) {
|
|
44999
|
+
const bytes3 = getBytes(randomBytes9, "randomBytes");
|
|
42763
45000
|
bytes3[6] = bytes3[6] & 15 | 64;
|
|
42764
45001
|
bytes3[8] = bytes3[8] & 63 | 128;
|
|
42765
45002
|
const value = hexlify(bytes3);
|
|
@@ -42793,7 +45030,7 @@ var init_utils = __esm({
|
|
|
42793
45030
|
});
|
|
42794
45031
|
|
|
42795
45032
|
// node_modules/ethers/lib.esm/crypto/crypto.js
|
|
42796
|
-
import { createHash as
|
|
45033
|
+
import { createHash as createHash9, createHmac, pbkdf2Sync, randomBytes as randomBytes6 } from "crypto";
|
|
42797
45034
|
var init_crypto2 = __esm({
|
|
42798
45035
|
"node_modules/ethers/lib.esm/crypto/crypto.js"() {
|
|
42799
45036
|
}
|
|
@@ -43447,7 +45684,7 @@ var init_pbkdf2 = __esm({
|
|
|
43447
45684
|
});
|
|
43448
45685
|
|
|
43449
45686
|
// node_modules/ethers/lib.esm/crypto/random.js
|
|
43450
|
-
function
|
|
45687
|
+
function randomBytes7(length) {
|
|
43451
45688
|
return __randomBytes(length);
|
|
43452
45689
|
}
|
|
43453
45690
|
var locked5, _randomBytes, __randomBytes;
|
|
@@ -43456,20 +45693,20 @@ var init_random = __esm({
|
|
|
43456
45693
|
init_crypto2();
|
|
43457
45694
|
locked5 = false;
|
|
43458
45695
|
_randomBytes = function(length) {
|
|
43459
|
-
return new Uint8Array(
|
|
45696
|
+
return new Uint8Array(randomBytes6(length));
|
|
43460
45697
|
};
|
|
43461
45698
|
__randomBytes = _randomBytes;
|
|
43462
|
-
|
|
43463
|
-
|
|
45699
|
+
randomBytes7._ = _randomBytes;
|
|
45700
|
+
randomBytes7.lock = function() {
|
|
43464
45701
|
locked5 = true;
|
|
43465
45702
|
};
|
|
43466
|
-
|
|
45703
|
+
randomBytes7.register = function(func) {
|
|
43467
45704
|
if (locked5) {
|
|
43468
45705
|
throw new Error("randomBytes is locked");
|
|
43469
45706
|
}
|
|
43470
45707
|
__randomBytes = func;
|
|
43471
45708
|
};
|
|
43472
|
-
Object.freeze(
|
|
45709
|
+
Object.freeze(randomBytes7);
|
|
43473
45710
|
}
|
|
43474
45711
|
});
|
|
43475
45712
|
|
|
@@ -44007,10 +46244,10 @@ var init_sha22 = __esm({
|
|
|
44007
46244
|
init_crypto2();
|
|
44008
46245
|
init_utils();
|
|
44009
46246
|
_sha256 = function(data) {
|
|
44010
|
-
return
|
|
46247
|
+
return createHash9("sha256").update(data).digest();
|
|
44011
46248
|
};
|
|
44012
46249
|
_sha512 = function(data) {
|
|
44013
|
-
return
|
|
46250
|
+
return createHash9("sha512").update(data).digest();
|
|
44014
46251
|
};
|
|
44015
46252
|
__sha256 = _sha256;
|
|
44016
46253
|
__sha512 = _sha512;
|
|
@@ -44117,7 +46354,7 @@ function wrapConstructor2(hashCons) {
|
|
|
44117
46354
|
hashC.create = () => hashCons();
|
|
44118
46355
|
return hashC;
|
|
44119
46356
|
}
|
|
44120
|
-
function
|
|
46357
|
+
function randomBytes8(bytesLength = 32) {
|
|
44121
46358
|
if (crypto2 && typeof crypto2.getRandomValues === "function") {
|
|
44122
46359
|
return crypto2.getRandomValues(new Uint8Array(bytesLength));
|
|
44123
46360
|
}
|
|
@@ -45656,7 +47893,7 @@ function weierstrass(curveDef) {
|
|
|
45656
47893
|
function prepSig(msgHash, privateKey, opts = defaultSigOpts) {
|
|
45657
47894
|
if (["recovered", "canonical"].some((k) => k in opts))
|
|
45658
47895
|
throw new Error("sign() legacy options not supported");
|
|
45659
|
-
const { hash: hash4, randomBytes:
|
|
47896
|
+
const { hash: hash4, randomBytes: randomBytes9 } = CURVE;
|
|
45660
47897
|
let { lowS, prehash, extraEntropy: ent } = opts;
|
|
45661
47898
|
if (lowS == null)
|
|
45662
47899
|
lowS = true;
|
|
@@ -45667,7 +47904,7 @@ function weierstrass(curveDef) {
|
|
|
45667
47904
|
const d = normPrivateKeyToScalar(privateKey);
|
|
45668
47905
|
const seedArgs = [int2octets(d), int2octets(h1int)];
|
|
45669
47906
|
if (ent != null) {
|
|
45670
|
-
const e = ent === true ?
|
|
47907
|
+
const e = ent === true ? randomBytes9(Fp2.BYTES) : ent;
|
|
45671
47908
|
seedArgs.push(ensureBytes("extraEntropy", e));
|
|
45672
47909
|
}
|
|
45673
47910
|
const seed = concatBytes2(...seedArgs);
|
|
@@ -45904,7 +48141,7 @@ function getHash(hash4) {
|
|
|
45904
48141
|
return {
|
|
45905
48142
|
hash: hash4,
|
|
45906
48143
|
hmac: (key, ...msgs) => hmac2(hash4, key, concatBytes(...msgs)),
|
|
45907
|
-
randomBytes:
|
|
48144
|
+
randomBytes: randomBytes8
|
|
45908
48145
|
};
|
|
45909
48146
|
}
|
|
45910
48147
|
function createCurve(curveDef, defHash) {
|
|
@@ -49878,7 +52115,7 @@ async function decryptKeystoreJson(json2, _password, progress) {
|
|
|
49878
52115
|
return getAccount(data, key);
|
|
49879
52116
|
}
|
|
49880
52117
|
function getEncryptKdfParams(options) {
|
|
49881
|
-
const salt = options.salt != null ? getBytes(options.salt, "options.salt") :
|
|
52118
|
+
const salt = options.salt != null ? getBytes(options.salt, "options.salt") : randomBytes7(32);
|
|
49882
52119
|
let N2 = 1 << 17, r = 8, p = 1;
|
|
49883
52120
|
if (options.scrypt) {
|
|
49884
52121
|
if (options.scrypt.N) {
|
|
@@ -49898,9 +52135,9 @@ function getEncryptKdfParams(options) {
|
|
|
49898
52135
|
}
|
|
49899
52136
|
function _encryptKeystore(key, kdf, account, options) {
|
|
49900
52137
|
const privateKey = getBytes(account.privateKey, "privateKey");
|
|
49901
|
-
const iv = options.iv != null ? getBytes(options.iv, "options.iv") :
|
|
52138
|
+
const iv = options.iv != null ? getBytes(options.iv, "options.iv") : randomBytes7(16);
|
|
49902
52139
|
assertArgument(iv.length === 16, "invalid options.iv length", "options.iv", options.iv);
|
|
49903
|
-
const uuidRandom = options.uuid != null ? getBytes(options.uuid, "options.uuid") :
|
|
52140
|
+
const uuidRandom = options.uuid != null ? getBytes(options.uuid, "options.uuid") : randomBytes7(16);
|
|
49904
52141
|
assertArgument(uuidRandom.length === 16, "invalid options.uuid length", "options.uuid", options.iv);
|
|
49905
52142
|
const derivedKey = key.slice(0, 16);
|
|
49906
52143
|
const macPrefix = key.slice(16, 32);
|
|
@@ -49934,7 +52171,7 @@ function _encryptKeystore(key, kdf, account, options) {
|
|
|
49934
52171
|
const locale = account.mnemonic.locale || "en";
|
|
49935
52172
|
const mnemonicKey = key.slice(32, 64);
|
|
49936
52173
|
const entropy = getBytes(account.mnemonic.entropy, "account.mnemonic.entropy");
|
|
49937
|
-
const mnemonicIv =
|
|
52174
|
+
const mnemonicIv = randomBytes7(16);
|
|
49938
52175
|
const mnemonicAesCtr = new CTR(mnemonicKey, mnemonicIv);
|
|
49939
52176
|
const mnemonicCiphertext = getBytes(mnemonicAesCtr.encrypt(entropy));
|
|
49940
52177
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -50272,7 +52509,7 @@ var init_hdwallet = __esm({
|
|
|
50272
52509
|
if (wordlist2 == null) {
|
|
50273
52510
|
wordlist2 = LangEn.wordlist();
|
|
50274
52511
|
}
|
|
50275
|
-
const mnemonic = Mnemonic.fromEntropy(
|
|
52512
|
+
const mnemonic = Mnemonic.fromEntropy(randomBytes7(16), password, wordlist2);
|
|
50276
52513
|
return _HDNodeWallet.#fromSeed(mnemonic.computeSeed(), mnemonic).derivePath(path);
|
|
50277
52514
|
}
|
|
50278
52515
|
/**
|
|
@@ -60625,7 +62862,7 @@ var headless_local_worker_exports = {};
|
|
|
60625
62862
|
__export(headless_local_worker_exports, {
|
|
60626
62863
|
createHeadlessLocalWorker: () => createHeadlessLocalWorker
|
|
60627
62864
|
});
|
|
60628
|
-
import { randomUUID as
|
|
62865
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
60629
62866
|
function objectOrNull3(value) {
|
|
60630
62867
|
return value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
60631
62868
|
}
|
|
@@ -61042,7 +63279,7 @@ function createHeadlessLocalWorker(options) {
|
|
|
61042
63279
|
const statusMatch = errorText.match(/\b([45]\d{2})\b/);
|
|
61043
63280
|
const statusCode = statusMatch ? Number(statusMatch[1]) : null;
|
|
61044
63281
|
const failedInvocation = normalizeAiInvocationTelemetry({
|
|
61045
|
-
client_invocation_id:
|
|
63282
|
+
client_invocation_id: randomUUID9(),
|
|
61046
63283
|
use_case: "trader",
|
|
61047
63284
|
role: "primary",
|
|
61048
63285
|
attempt_index: 0,
|
|
@@ -61098,7 +63335,7 @@ function createHeadlessLocalWorker(options) {
|
|
|
61098
63335
|
billable_cached_input_tokens: normalizedUsage.cached_input_tokens
|
|
61099
63336
|
};
|
|
61100
63337
|
const invocation = normalizeAiInvocationTelemetry({
|
|
61101
|
-
client_invocation_id:
|
|
63338
|
+
client_invocation_id: randomUUID9(),
|
|
61102
63339
|
use_case: "trader",
|
|
61103
63340
|
role: "primary",
|
|
61104
63341
|
attempt_index: 0,
|
|
@@ -61317,7 +63554,7 @@ var vtx_exports = {};
|
|
|
61317
63554
|
__export(vtx_exports, {
|
|
61318
63555
|
runVtxCli: () => runVtxCli
|
|
61319
63556
|
});
|
|
61320
|
-
import { randomUUID as
|
|
63557
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
61321
63558
|
import { spawn as spawn8 } from "node:child_process";
|
|
61322
63559
|
function render2(value, json2) {
|
|
61323
63560
|
if (json2) {
|
|
@@ -61731,8 +63968,8 @@ async function runVtxCli(argv2, env = process.env) {
|
|
|
61731
63968
|
});
|
|
61732
63969
|
return { exitCode: 0, stdout: render2(redactCliOutput(response2), json2), stderr: "" };
|
|
61733
63970
|
}
|
|
61734
|
-
const runtimeSessionId =
|
|
61735
|
-
const deviceId = config2.runtimeDeviceId ??
|
|
63971
|
+
const runtimeSessionId = randomUUID10();
|
|
63972
|
+
const deviceId = config2.runtimeDeviceId ?? randomUUID10();
|
|
61736
63973
|
const response = await client.startRuntime(profileId, {
|
|
61737
63974
|
session_id: runtimeSessionId,
|
|
61738
63975
|
device_id: deviceId,
|