subconscious-cli 4.1.2 → 4.1.4
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/bin/agents.js +28 -6
- package/bin/model-capabilities.js +11 -0
- package/bin/native/subc-tui-darwin-amd64 +0 -0
- package/bin/native/subc-tui-darwin-arm64 +0 -0
- package/bin/native/subc-tui-linux-amd64 +0 -0
- package/bin/native/subc-tui-linux-arm64 +0 -0
- package/bin/native/subc-tui-windows-amd64.exe +0 -0
- package/bin/native/subc-tui-windows-arm64.exe +0 -0
- package/bin/profiles.js +25 -0
- package/bin/registry.generated.json +26 -2
- package/bin/runbook/codex/hooks-lib.sh +32 -2
- package/bin/runbook/codex/install.sh +10 -0
- package/bin/runbook/codex/run.sh +119 -57
- package/bin/runbook/copilot/install.sh +8 -3
- package/bin/runbook/cursor/install.sh +2 -1
- package/bin/runbook/deepseek-harness/run.sh +8 -1
- package/bin/runbook/model-capabilities.generated.sh +9 -0
- package/bin/runbook/opencode/install.sh +8 -2
- package/bin/runbook/opencode/run.sh +8 -2
- package/bin/runbook/pi/install.sh +8 -2
- package/bin/windows/launch.js +7 -2
- package/bin/windows/setup.js +6 -2
- package/package.json +2 -2
package/bin/agents.js
CHANGED
|
@@ -32,6 +32,15 @@ import { compareVersions } from './update-check.js';
|
|
|
32
32
|
|
|
33
33
|
export const MIN_CLAUDE_CODE_VERSION = '2.1.242';
|
|
34
34
|
|
|
35
|
+
// First Codex that honours `multi_agent_version: "v2"` in the model catalog,
|
|
36
|
+
// found by installing each release and reading what it advertises: 0.142.5 and
|
|
37
|
+
// below offer no subagent namespace at all, 0.143.0 offers `collaboration`.
|
|
38
|
+
//
|
|
39
|
+
// Below this the catalog field is not rejected, it is ignored - the run simply
|
|
40
|
+
// has no subagents and nothing says why. That silence is the reason for a
|
|
41
|
+
// version gate rather than a note in the docs.
|
|
42
|
+
export const MIN_CODEX_VERSION = '0.143.0';
|
|
43
|
+
|
|
35
44
|
// --- Registry (single source of truth, generated copy shipped in the package).
|
|
36
45
|
const registry = JSON.parse(
|
|
37
46
|
readFileSync(new URL('./registry.generated.json', import.meta.url), 'utf-8'),
|
|
@@ -193,10 +202,10 @@ const AGENT_HELP = {
|
|
|
193
202
|
codex: {
|
|
194
203
|
usage: 'subc [-p NAME] codex [help|install|status|uninstall] [Codex arguments...]',
|
|
195
204
|
behavior:
|
|
196
|
-
'Launches Codex with a temporary Subconscious provider catalog. Compaction hooks are merged into ~/.codex/hooks.json and removed with subc codex uninstall.',
|
|
205
|
+
'Launches Codex with a temporary Subconscious provider catalog. Compaction hooks are merged into ~/.codex/hooks.json on first launch and removed with subc codex uninstall; Codex will not run them until you trust them with /hooks once.',
|
|
197
206
|
options: [
|
|
198
207
|
['help', 'Show this help'],
|
|
199
|
-
['install', 'Install
|
|
208
|
+
['install', 'Install the Subconscious compaction hooks (then trust with /hooks)'],
|
|
200
209
|
['status', 'Inspect the installed compaction hooks'],
|
|
201
210
|
['uninstall', 'Remove only the Subconscious Codex hooks'],
|
|
202
211
|
['--model MODEL', 'Override the profile model for this launch'],
|
|
@@ -205,7 +214,9 @@ const AGENT_HELP = {
|
|
|
205
214
|
['--auto-compact-token-limit N', 'Override the automatic compaction threshold'],
|
|
206
215
|
['--reasoning-effort LEVEL', 'Use none, low, medium, high, or max'],
|
|
207
216
|
['--external-tools', 'Enable Codex apps/plugins for this launch'],
|
|
208
|
-
['--
|
|
217
|
+
['--stream-idle-timeout MS', 'Allow a longer silent think before timing out'],
|
|
218
|
+
['--max-subagents N', 'Subagents allowed to run at once (default 4)'],
|
|
219
|
+
['--subagent-effort LEVEL', 'Effort for subagents, separate from the parent'],
|
|
209
220
|
['-- ARGS...', 'Pass remaining arguments to Codex'],
|
|
210
221
|
],
|
|
211
222
|
},
|
|
@@ -625,6 +636,10 @@ export function parseClaudeVersion(text) {
|
|
|
625
636
|
}
|
|
626
637
|
|
|
627
638
|
export function claudeVersionNeedsUpgrade(installed, minimum = MIN_CLAUDE_CODE_VERSION) {
|
|
639
|
+
return versionNeedsUpgrade(installed, minimum);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
export function versionNeedsUpgrade(installed, minimum) {
|
|
628
643
|
return Boolean(installed && minimum && compareVersions(installed, minimum) < 0);
|
|
629
644
|
}
|
|
630
645
|
|
|
@@ -649,13 +664,20 @@ export function readClaudeVersion(bin, binDir, options = {}) {
|
|
|
649
664
|
}
|
|
650
665
|
}
|
|
651
666
|
|
|
667
|
+
const MINIMUM_VERSIONS = {
|
|
668
|
+
'claude-code': { minimum: MIN_CLAUDE_CODE_VERSION, label: 'Claude Code' },
|
|
669
|
+
// Below this, subagents are silently absent rather than broken.
|
|
670
|
+
codex: { minimum: MIN_CODEX_VERSION, label: 'Codex' },
|
|
671
|
+
};
|
|
672
|
+
|
|
652
673
|
async function ensureClaudeCompatible(agent, binDir) {
|
|
653
|
-
|
|
674
|
+
const requirement = MINIMUM_VERSIONS[agent.id];
|
|
675
|
+
if (!requirement) return;
|
|
654
676
|
const version = readClaudeVersion(agent.bin, binDir);
|
|
655
|
-
if (!
|
|
677
|
+
if (!versionNeedsUpgrade(version, requirement.minimum)) return;
|
|
656
678
|
|
|
657
679
|
console.error(
|
|
658
|
-
`\n Minimum supported
|
|
680
|
+
`\n Minimum supported ${requirement.label} version is ${requirement.minimum}. Your version is ${version}. Upgrade to get the best experience.\n`,
|
|
659
681
|
);
|
|
660
682
|
console.error(` Upgrade it with:`);
|
|
661
683
|
console.error(` ${c.cyan}${agent.install}${c.reset}`);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
// The models endpoint currently supplies IDs, not modality metadata. Keep
|
|
4
|
+
// explicit capabilities in the same registry used to generate the Unix lookup.
|
|
5
|
+
const { modelCapabilities = {} } = JSON.parse(
|
|
6
|
+
readFileSync(new URL('./registry.generated.json', import.meta.url), 'utf8'),
|
|
7
|
+
);
|
|
8
|
+
|
|
9
|
+
export function modelSupportsVision(modelId) {
|
|
10
|
+
return Object.hasOwn(modelCapabilities, modelId) && modelCapabilities[modelId].vision === true;
|
|
11
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/bin/profiles.js
CHANGED
|
@@ -144,6 +144,28 @@ const SETTINGS = {
|
|
|
144
144
|
type: 'integer',
|
|
145
145
|
min: 1,
|
|
146
146
|
},
|
|
147
|
+
CODEX_SUBAGENT_REASONING_EFFORT: {
|
|
148
|
+
key: 'CODEX_SUBAGENT_REASONING_EFFORT',
|
|
149
|
+
label: 'Subagent reasoning effort',
|
|
150
|
+
description:
|
|
151
|
+
'Effort for Codex subagents, set separately from the parent: a marathon model at max thinks for minutes without emitting a token, and a subagent turn is one uninterrupted think, so inheriting max makes every delegated subtask look like a hang.',
|
|
152
|
+
type: 'text',
|
|
153
|
+
},
|
|
154
|
+
CODEX_MULTI_AGENT_VERSION: {
|
|
155
|
+
key: 'CODEX_MULTI_AGENT_VERSION',
|
|
156
|
+
label: 'Codex multi-agent version',
|
|
157
|
+
description:
|
|
158
|
+
'Which subagent implementation Codex offers: v2 gives the collaboration tools. Leave empty to turn subagents off entirely.',
|
|
159
|
+
type: 'text',
|
|
160
|
+
},
|
|
161
|
+
CODEX_STREAM_IDLE_TIMEOUT_MS: {
|
|
162
|
+
key: 'CODEX_STREAM_IDLE_TIMEOUT_MS',
|
|
163
|
+
label: 'Stream idle timeout (ms)',
|
|
164
|
+
description:
|
|
165
|
+
'How long Codex waits on a silent stream before giving up. Needs to exceed the longest think the model will take.',
|
|
166
|
+
type: 'integer',
|
|
167
|
+
min: 1,
|
|
168
|
+
},
|
|
147
169
|
MAX_SUBAGENT_SPAWN_DEPTH: {
|
|
148
170
|
key: 'MAX_SUBAGENT_SPAWN_DEPTH',
|
|
149
171
|
label: 'Subagent spawn depth',
|
|
@@ -305,6 +327,9 @@ const AGENT_SETTING_KEYS = {
|
|
|
305
327
|
'CODEX_AUTO_COMPACT_TOKEN_LIMIT',
|
|
306
328
|
'CODEX_REASONING_EFFORT',
|
|
307
329
|
'CODEX_EXTERNAL_TOOLS',
|
|
330
|
+
'CODEX_STREAM_IDLE_TIMEOUT_MS',
|
|
331
|
+
'CODEX_MULTI_AGENT_VERSION',
|
|
332
|
+
'CODEX_SUBAGENT_REASONING_EFFORT',
|
|
308
333
|
'MAX_CONCURRENT_SUBAGENTS',
|
|
309
334
|
],
|
|
310
335
|
opencode: ['OPENCODE_API_KEY', 'OPENCODE_CONTEXT_LIMIT', 'OPENCODE_OUTPUT_LIMIT'],
|
|
@@ -6,13 +6,19 @@
|
|
|
6
6
|
"subconscious/glm-5.3-marathon",
|
|
7
7
|
"subconscious/glm-5.2",
|
|
8
8
|
"subconscious/tim-qwen3.6-27b",
|
|
9
|
-
"subconscious/deepseek-v4-flash-marathon"
|
|
9
|
+
"subconscious/deepseek-v4-flash-marathon",
|
|
10
|
+
"subconscious/deepseek-v4.1-flash-marathon"
|
|
10
11
|
],
|
|
11
12
|
"baseUrl": "https://api.subconscious.dev",
|
|
12
13
|
"baseUrlV1": "https://api.subconscious.dev/v1",
|
|
13
14
|
"keyPlaceholder": "your_key",
|
|
14
15
|
"platformUrl": "https://subconscious.dev/platform"
|
|
15
16
|
},
|
|
17
|
+
"modelCapabilities": {
|
|
18
|
+
"subconscious/deepseek-v4.1-flash-marathon": {
|
|
19
|
+
"vision": true
|
|
20
|
+
}
|
|
21
|
+
},
|
|
16
22
|
"agents": [
|
|
17
23
|
{
|
|
18
24
|
"id": "subconscious-code",
|
|
@@ -161,7 +167,7 @@
|
|
|
161
167
|
"uninstall"
|
|
162
168
|
]
|
|
163
169
|
},
|
|
164
|
-
"launch": "codex -c model={model} -c model_provider=subconscious -c web_search=disabled -c model_providers.subconscious.name=Subconscious -c model_providers.subconscious.base_url={baseUrlV1} -c model_providers.subconscious.wire_api=responses -c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY -c model_providers.subconscious.stream_idle_timeout_ms=
|
|
170
|
+
"launch": "codex -c model={model} -c model_provider=subconscious -c web_search=disabled -c model_providers.subconscious.name=Subconscious -c model_providers.subconscious.base_url={baseUrlV1} -c model_providers.subconscious.wire_api=responses -c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY -c model_providers.subconscious.stream_idle_timeout_ms=900000",
|
|
165
171
|
"env": {
|
|
166
172
|
"SUBCONSCIOUS_API_KEY": "{apiKey}",
|
|
167
173
|
"SUBCONSCIOUS_GATEWAY_URL": "{baseUrl}"
|
|
@@ -253,6 +259,24 @@
|
|
|
253
259
|
"context": 5000000,
|
|
254
260
|
"output": 65536
|
|
255
261
|
}
|
|
262
|
+
},
|
|
263
|
+
"subconscious/deepseek-v4.1-flash-marathon": {
|
|
264
|
+
"name": "subconscious/deepseek-v4.1-flash-marathon",
|
|
265
|
+
"tools": true,
|
|
266
|
+
"attachment": true,
|
|
267
|
+
"modalities": {
|
|
268
|
+
"input": [
|
|
269
|
+
"text",
|
|
270
|
+
"image"
|
|
271
|
+
],
|
|
272
|
+
"output": [
|
|
273
|
+
"text"
|
|
274
|
+
]
|
|
275
|
+
},
|
|
276
|
+
"limit": {
|
|
277
|
+
"context": 5000000,
|
|
278
|
+
"output": 65536
|
|
279
|
+
}
|
|
256
280
|
}
|
|
257
281
|
}
|
|
258
282
|
}
|
|
@@ -61,6 +61,30 @@ EOF
|
|
|
61
61
|
chmod 600 "$HOOKS_ENV_FILE"
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
+
# True when our hooks, hook script and env file are all already in place and
|
|
65
|
+
# current, so there is nothing to write.
|
|
66
|
+
#
|
|
67
|
+
# This matters more than it looks. Codex asks the user to trust a hook before
|
|
68
|
+
# it will run one, and it decides what is "new" from what is on disk. Rewriting
|
|
69
|
+
# an identical hook on every single launch meant the trust prompt never went
|
|
70
|
+
# away and the compaction hooks never actually ran - we were re-introducing
|
|
71
|
+
# ourselves as a stranger several times a day.
|
|
72
|
+
codex_hooks_current() {
|
|
73
|
+
[[ -f "$HOOKS_JSON" ]] || return 1
|
|
74
|
+
codex_hooks_json_valid || return 1
|
|
75
|
+
[[ -x "$HOOK_DST" ]] || return 1
|
|
76
|
+
[[ -f "${HOOK_SRC:-}" ]] || return 1
|
|
77
|
+
cmp -s "$HOOK_SRC" "$HOOK_DST" || return 1
|
|
78
|
+
[[ -f "$HOOKS_ENV_FILE" ]] || return 1
|
|
79
|
+
grep -q "SUBCONSCIOUS_GATEWAY_URL='${GATEWAY_URL%/}'" "$HOOKS_ENV_FILE" || return 1
|
|
80
|
+
grep -q "SUBCONSCIOUS_API_KEY='${API_KEY}'" "$HOOKS_ENV_FILE" || return 1
|
|
81
|
+
# Our entry present under both compaction events, and exactly once each.
|
|
82
|
+
jq -e --arg m "$MARKER" '
|
|
83
|
+
def ours: [ .[]?.hooks[]? | select((.command // "") | tostring | contains($m)) ] | length;
|
|
84
|
+
(.hooks.PreCompact | ours) == 1 and (.hooks.PostCompact | ours) == 1
|
|
85
|
+
' "$HOOKS_JSON" >/dev/null 2>&1
|
|
86
|
+
}
|
|
87
|
+
|
|
64
88
|
# codex_ensure_hooks [strict|best-effort]
|
|
65
89
|
codex_ensure_hooks() {
|
|
66
90
|
local mode="${1:-strict}"
|
|
@@ -91,12 +115,18 @@ codex_ensure_hooks() {
|
|
|
91
115
|
if [[ ! -f "$HOOKS_JSON" ]]; then
|
|
92
116
|
printf '%s\n' '{"hooks":{}}' >"$HOOKS_JSON"
|
|
93
117
|
fi
|
|
118
|
+
if codex_hooks_current; then
|
|
119
|
+
# Already installed and unchanged. Saying nothing is the point: a message
|
|
120
|
+
# on every launch trains the user to ignore it, and rewriting the file
|
|
121
|
+
# would reset the trust they have already granted.
|
|
122
|
+
return 0
|
|
123
|
+
fi
|
|
94
124
|
codex_write_hook_script
|
|
95
125
|
codex_write_hooks_env
|
|
96
126
|
codex_strip_hook_entries
|
|
97
127
|
codex_append_hook_groups
|
|
98
|
-
echo "
|
|
99
|
-
echo "
|
|
128
|
+
echo "Installed Subconscious compaction hooks in $HOOKS_JSON"
|
|
129
|
+
echo "These do not run until you trust them: type /hooks inside Codex once."
|
|
100
130
|
}
|
|
101
131
|
|
|
102
132
|
codex_uninstall_hooks() {
|
|
@@ -33,6 +33,16 @@ Usage:
|
|
|
33
33
|
|
|
34
34
|
Merges Subconscious compaction hooks into ~/.codex/hooks.json. Does not write
|
|
35
35
|
config.toml. Launch Codex with subc codex.
|
|
36
|
+
|
|
37
|
+
The hooks report compaction start and end to the gateway, which is what lets a
|
|
38
|
+
conversation's turns stay correlated across a compaction boundary.
|
|
39
|
+
|
|
40
|
+
Codex will not run a hook until you trust it. After installing, type /hooks
|
|
41
|
+
inside Codex once and approve them; until then they are present but inert.
|
|
42
|
+
Non-interactive runs have nobody to ask, so `codex exec` can only run them with
|
|
43
|
+
--dangerously-bypass-hook-trust, which is yours to opt into and is never passed
|
|
44
|
+
for you. Fleet installs should ship the hooks through Codex's managed
|
|
45
|
+
(MDM) configuration, which is trusted without prompting.
|
|
36
46
|
EOF
|
|
37
47
|
}
|
|
38
48
|
|
package/bin/runbook/codex/run.sh
CHANGED
|
@@ -6,20 +6,24 @@
|
|
|
6
6
|
# The model catalog (needed to suppress the "model metadata not found" warning)
|
|
7
7
|
# is written to a temp file that is cleaned up on exit.
|
|
8
8
|
#
|
|
9
|
-
# Subagents are
|
|
10
|
-
#
|
|
11
|
-
# "
|
|
12
|
-
#
|
|
9
|
+
# Subagents are ON by default. The per-model `multi_agent_version` catalog
|
|
10
|
+
# field selects WHICH implementation Codex offers, not whether it offers one:
|
|
11
|
+
# "v2" gives the `collaboration` namespace, and an empty value falls back to
|
|
12
|
+
# the older `multi_agent_v1` namespace rather than turning subagents off.
|
|
13
|
+
# Only `agents.enabled=false` actually disables them, so clearing
|
|
14
|
+
# CODEX_MULTI_AGENT_VERSION does both.
|
|
13
15
|
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
16
|
+
# This needs a gateway that round-trips Codex's namespaced tools. Codex sends
|
|
17
|
+
# them as `type: "namespace"` and resolves an incoming call by namespace plus
|
|
18
|
+
# name, so a gateway that flattens the namespace for the model must restore it
|
|
19
|
+
# on the way back, or every call fails with "unsupported call: spawn_agent".
|
|
17
20
|
#
|
|
18
21
|
# Usage:
|
|
19
22
|
# ./run.sh # uses GATEWAY_URL/API_KEY from ../.env
|
|
20
23
|
# ./run.sh --context-window 5000000 -- --resume
|
|
21
|
-
# ./run.sh --
|
|
22
|
-
# ./run.sh --subagents
|
|
24
|
+
# ./run.sh --stream-idle-timeout 1800000 # allow a 30min silent think
|
|
25
|
+
# ./run.sh --max-subagents 12 # raise the concurrent-subagent ceiling
|
|
26
|
+
# ./run.sh --subagent-effort low # cheaper subagents than the parent
|
|
23
27
|
# ./run.sh --external-tools # include Codex apps/plugins (may exceed gateway tool limits)
|
|
24
28
|
#
|
|
25
29
|
# Config: copy ../env.example to ../.env and edit. .env is gitignored.
|
|
@@ -31,6 +35,7 @@
|
|
|
31
35
|
set -euo pipefail
|
|
32
36
|
|
|
33
37
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
38
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
34
39
|
|
|
35
40
|
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
36
41
|
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
@@ -40,16 +45,31 @@ if [[ -f "$SHARED_ENV" ]]; then set -a; source "$SHARED_ENV"; set +a; fi
|
|
|
40
45
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
41
46
|
API_KEY="${CODEX_API_KEY:-${API_KEY:-}}"
|
|
42
47
|
MODEL="${MODEL:-subconscious/glm-5.3-marathon}"
|
|
43
|
-
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-
|
|
44
|
-
|
|
48
|
+
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-}"
|
|
49
|
+
# Effort for spawned agents, independent of the parent's. Empty inherits the
|
|
50
|
+
# Codex default. See the note above SUBAGENT_ARGS for why max is a poor choice.
|
|
51
|
+
#
|
|
52
|
+
# Low rather than medium: the gateway rounds medium up to high for GLM, and at
|
|
53
|
+
# high a subagent handed an open-ended task keeps deliberating without ever
|
|
54
|
+
# writing the closing `</think>`. The turn then comes back as one long block of
|
|
55
|
+
# prose with no tool call, so the agent reports success having produced no
|
|
56
|
+
# files. Measured against the worker on one broad task: low closed and called a
|
|
57
|
+
# tool in ~1.5k characters, high ran past 76k and was still going.
|
|
58
|
+
CODEX_SUBAGENT_REASONING_EFFORT="${CODEX_SUBAGENT_REASONING_EFFORT-low}"
|
|
45
59
|
EXTERNAL_TOOLS="${CODEX_EXTERNAL_TOOLS:-false}"
|
|
46
60
|
CODEX_CONTEXT_WINDOW="${CODEX_CONTEXT_WINDOW:-5000000}"
|
|
47
61
|
CODEX_MAX_CONTEXT_WINDOW="${CODEX_MAX_CONTEXT_WINDOW:-}"
|
|
48
62
|
CODEX_AUTO_COMPACT_TOKEN_LIMIT="${CODEX_AUTO_COMPACT_TOKEN_LIMIT:-4500000}"
|
|
49
63
|
CODEX_REASONING_EFFORT="${CODEX_REASONING_EFFORT:-max}"
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
|
|
64
|
+
# How long Codex waits on a silent stream before giving up. The marathon models
|
|
65
|
+
# at max reasoning effort routinely think for longer than five minutes without
|
|
66
|
+
# emitting a token, and a subagent's turn is one uninterrupted think with no
|
|
67
|
+
# visible progress, so the old 300s ceiling cut off work that was still running.
|
|
68
|
+
CODEX_STREAM_IDLE_TIMEOUT_MS="${CODEX_STREAM_IDLE_TIMEOUT_MS:-900000}"
|
|
69
|
+
# Codex gates its subagent tools on this per-model catalog field. Only "v2" is
|
|
70
|
+
# honored by current releases; "v1" registers nothing. Set to empty to opt out.
|
|
71
|
+
# Unset defaults to v2; an explicitly empty value opts out, so use `-` not `:-`.
|
|
72
|
+
CODEX_MULTI_AGENT_VERSION="${CODEX_MULTI_AGENT_VERSION-v2}"
|
|
53
73
|
|
|
54
74
|
# Parse args (only when executed, not sourced)
|
|
55
75
|
PASSTHRU=()
|
|
@@ -72,9 +92,17 @@ if [[ "${BASH_SOURCE[0]:-$0}" == "${0}" ]]; then
|
|
|
72
92
|
CODEX_REASONING_EFFORT="${2:-}"
|
|
73
93
|
shift 2
|
|
74
94
|
;;
|
|
75
|
-
--
|
|
76
|
-
|
|
77
|
-
shift
|
|
95
|
+
--stream-idle-timeout)
|
|
96
|
+
CODEX_STREAM_IDLE_TIMEOUT_MS="${2:-}"
|
|
97
|
+
shift 2
|
|
98
|
+
;;
|
|
99
|
+
--max-subagents)
|
|
100
|
+
MAX_CONCURRENT_SUBAGENTS="${2:-}"
|
|
101
|
+
shift 2
|
|
102
|
+
;;
|
|
103
|
+
--subagent-effort)
|
|
104
|
+
CODEX_SUBAGENT_REASONING_EFFORT="${2:-}"
|
|
105
|
+
shift 2
|
|
78
106
|
;;
|
|
79
107
|
--external-tools)
|
|
80
108
|
EXTERNAL_TOOLS=true
|
|
@@ -105,7 +133,8 @@ esac
|
|
|
105
133
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
106
134
|
subconscious/glm-5.2
|
|
107
135
|
subconscious/tim-qwen3.6-27b
|
|
108
|
-
subconscious/deepseek-v4-flash-marathon
|
|
136
|
+
subconscious/deepseek-v4-flash-marathon
|
|
137
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
109
138
|
SUPPORTED_MODELS=()
|
|
110
139
|
|
|
111
140
|
add_supported_model() {
|
|
@@ -132,10 +161,17 @@ while IFS= read -r model_id; do
|
|
|
132
161
|
done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
133
162
|
|
|
134
163
|
write_model_catalog() {
|
|
135
|
-
local catalog_file="$1" model_id index=0
|
|
164
|
+
local catalog_file="$1" model_id vision_fields index=0 multi_agent_json="null"
|
|
165
|
+
if [[ -n "$CODEX_MULTI_AGENT_VERSION" ]]; then
|
|
166
|
+
multi_agent_json="\"${CODEX_MULTI_AGENT_VERSION}\""
|
|
167
|
+
fi
|
|
136
168
|
{
|
|
137
169
|
printf '{\n "models": [\n'
|
|
138
170
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
171
|
+
vision_fields=""
|
|
172
|
+
if subc_model_supports_vision "$model_id"; then
|
|
173
|
+
vision_fields=', "input_modalities": ["text", "image"]'
|
|
174
|
+
fi
|
|
139
175
|
if [[ "$index" -gt 0 ]]; then
|
|
140
176
|
printf ',\n'
|
|
141
177
|
fi
|
|
@@ -148,7 +184,13 @@ write_model_catalog() {
|
|
|
148
184
|
"max_context_window": ${CODEX_MAX_CONTEXT_WINDOW},
|
|
149
185
|
"auto_compact_token_limit": ${CODEX_AUTO_COMPACT_TOKEN_LIMIT},
|
|
150
186
|
"effective_context_window_percent": 95,
|
|
151
|
-
"supported_reasoning_levels": [
|
|
187
|
+
"supported_reasoning_levels": [
|
|
188
|
+
{ "effort": "none", "description": "No additional reasoning" },
|
|
189
|
+
{ "effort": "low", "description": "Fast responses with lighter reasoning" },
|
|
190
|
+
{ "effort": "medium", "description": "Balances speed and reasoning depth" },
|
|
191
|
+
{ "effort": "high", "description": "Greater reasoning depth for complex problems" },
|
|
192
|
+
{ "effort": "max", "description": "Maximum reasoning depth for the hardest problems" }
|
|
193
|
+
],
|
|
152
194
|
"shell_type": "shell_command",
|
|
153
195
|
"visibility": "list",
|
|
154
196
|
"supported_in_api": true,
|
|
@@ -169,7 +211,9 @@ write_model_catalog() {
|
|
|
169
211
|
"apply_patch_tool_type": "freeform",
|
|
170
212
|
"truncation_policy": { "mode": "tokens", "limit": 10000 },
|
|
171
213
|
"supports_parallel_tool_calls": true,
|
|
172
|
-
"
|
|
214
|
+
"multi_agent_version": ${multi_agent_json},
|
|
215
|
+
"use_responses_lite": false,
|
|
216
|
+
"experimental_supported_tools": []${vision_fields}
|
|
173
217
|
}
|
|
174
218
|
EOF
|
|
175
219
|
index=$((index + 1))
|
|
@@ -191,6 +235,41 @@ if [[ "$EXTERNAL_TOOLS" != "true" ]]; then
|
|
|
191
235
|
)
|
|
192
236
|
fi
|
|
193
237
|
|
|
238
|
+
# Bound the subagent tree when the catalog turns it on. Codex still only spawns
|
|
239
|
+
# a subagent when the user asks for one; these are ceilings, not defaults.
|
|
240
|
+
#
|
|
241
|
+
# Codex documents no nesting-depth limit, so a subagent can spawn its own
|
|
242
|
+
# subagent and the tree can grow deeper than you asked for. Capping concurrency
|
|
243
|
+
# is the only lever available.
|
|
244
|
+
#
|
|
245
|
+
# Subagent reasoning effort is set separately from the parent's on purpose: the
|
|
246
|
+
# marathon models at max effort think for many minutes without emitting a
|
|
247
|
+
# token, and a subagent turn is one uninterrupted think, so inheriting max
|
|
248
|
+
# makes every delegated subtask look like a hang.
|
|
249
|
+
# Applied after argument parsing so --max-subagents can win. Four is a floor
|
|
250
|
+
# rather than a considered limit: Codex's own default is three, and exceeding
|
|
251
|
+
# either one fails the spawn outright rather than queueing it, so a run that
|
|
252
|
+
# wants more should say so instead of collecting retries.
|
|
253
|
+
MAX_CONCURRENT_SUBAGENTS="${MAX_CONCURRENT_SUBAGENTS:-4}"
|
|
254
|
+
|
|
255
|
+
SUBAGENT_ARGS=()
|
|
256
|
+
if [[ -z "$CODEX_MULTI_AGENT_VERSION" ]]; then
|
|
257
|
+
# Clearing the catalog field alone only downgrades Codex to multi-agent v1,
|
|
258
|
+
# whose tools this gateway has never been exercised against. Turn the
|
|
259
|
+
# feature off outright instead.
|
|
260
|
+
SUBAGENT_ARGS=(-c agents.enabled=false)
|
|
261
|
+
else
|
|
262
|
+
SUBAGENT_ARGS=(
|
|
263
|
+
-c agents.max_concurrent_threads_per_session="${MAX_CONCURRENT_SUBAGENTS}"
|
|
264
|
+
-c agents.interrupt_message=true
|
|
265
|
+
)
|
|
266
|
+
if [[ -n "$CODEX_SUBAGENT_REASONING_EFFORT" ]]; then
|
|
267
|
+
SUBAGENT_ARGS+=(
|
|
268
|
+
-c agents.default_subagent_reasoning_effort="${CODEX_SUBAGENT_REASONING_EFFORT}"
|
|
269
|
+
)
|
|
270
|
+
fi
|
|
271
|
+
fi
|
|
272
|
+
|
|
194
273
|
if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
|
|
195
274
|
echo "error: GATEWAY_URL and API_KEY must be set in ../.env" >&2
|
|
196
275
|
exit 1
|
|
@@ -200,6 +279,10 @@ export SUBCONSCIOUS_API_KEY="$API_KEY"
|
|
|
200
279
|
export SUBCONSCIOUS_GATEWAY_URL="${GATEWAY_URL%/}"
|
|
201
280
|
|
|
202
281
|
# Merge compaction hooks without replacing ~/.codex/hooks.json or config.toml.
|
|
282
|
+
# `codex_ensure_hooks` returns early when they are already current, so a launch
|
|
283
|
+
# that changes nothing writes nothing: Codex decides what counts as a new hook
|
|
284
|
+
# from what is on disk, and rewriting an identical one reset the trust the user
|
|
285
|
+
# had already granted.
|
|
203
286
|
HOOK_SRC="${SCRIPT_DIR}/hook.sh"
|
|
204
287
|
# shellcheck source=hooks-lib.sh
|
|
205
288
|
source "${SCRIPT_DIR}/hooks-lib.sh"
|
|
@@ -214,43 +297,22 @@ write_model_catalog "$CATALOG_FILE"
|
|
|
214
297
|
|
|
215
298
|
# If sourced, just export env and return.
|
|
216
299
|
if [[ "${BASH_SOURCE[0]:-$0}" != "${0}" ]]; then
|
|
217
|
-
export GATEWAY_URL CATALOG_FILE MAX_CONCURRENT_SUBAGENTS
|
|
300
|
+
export GATEWAY_URL CATALOG_FILE MAX_CONCURRENT_SUBAGENTS CODEX_SUBAGENT_REASONING_EFFORT
|
|
218
301
|
return 0 2>/dev/null || true
|
|
219
302
|
fi
|
|
220
303
|
|
|
221
304
|
# Ephemeral config via -c flags — nothing is written to ~/.codex/config.toml.
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
-c model_providers.subconscious.name=Subconscious \
|
|
237
|
-
-c model_providers.subconscious.base_url="${GATEWAY_URL}/v1" \
|
|
238
|
-
-c model_providers.subconscious.wire_api=responses \
|
|
239
|
-
-c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY \
|
|
240
|
-
-c model_providers.subconscious.stream_idle_timeout_ms=300000 \
|
|
241
|
-
${PASSTHRU[@]+"${PASSTHRU[@]}"}
|
|
242
|
-
else
|
|
243
|
-
exec codex \
|
|
244
|
-
-c model="${MODEL}" \
|
|
245
|
-
-c model_provider=subconscious \
|
|
246
|
-
-c model_catalog_json="${CATALOG_FILE}" \
|
|
247
|
-
-c model_reasoning_effort="${CODEX_REASONING_EFFORT}" \
|
|
248
|
-
-c web_search=disabled \
|
|
249
|
-
${EXTERNAL_TOOL_ARGS[@]+"${EXTERNAL_TOOL_ARGS[@]}"} \
|
|
250
|
-
-c model_providers.subconscious.name=Subconscious \
|
|
251
|
-
-c model_providers.subconscious.base_url="${GATEWAY_URL}/v1" \
|
|
252
|
-
-c model_providers.subconscious.wire_api=responses \
|
|
253
|
-
-c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY \
|
|
254
|
-
-c model_providers.subconscious.stream_idle_timeout_ms=300000 \
|
|
255
|
-
${PASSTHRU[@]+"${PASSTHRU[@]}"}
|
|
256
|
-
fi
|
|
305
|
+
exec codex \
|
|
306
|
+
-c model="${MODEL}" \
|
|
307
|
+
-c model_provider=subconscious \
|
|
308
|
+
-c model_catalog_json="${CATALOG_FILE}" \
|
|
309
|
+
-c model_reasoning_effort="${CODEX_REASONING_EFFORT}" \
|
|
310
|
+
-c web_search=disabled \
|
|
311
|
+
${EXTERNAL_TOOL_ARGS[@]+"${EXTERNAL_TOOL_ARGS[@]}"} \
|
|
312
|
+
${SUBAGENT_ARGS[@]+"${SUBAGENT_ARGS[@]}"} \
|
|
313
|
+
-c model_providers.subconscious.name=Subconscious \
|
|
314
|
+
-c model_providers.subconscious.base_url="${GATEWAY_URL}/v1" \
|
|
315
|
+
-c model_providers.subconscious.wire_api=responses \
|
|
316
|
+
-c model_providers.subconscious.env_key=SUBCONSCIOUS_API_KEY \
|
|
317
|
+
-c model_providers.subconscious.stream_idle_timeout_ms="${CODEX_STREAM_IDLE_TIMEOUT_MS}" \
|
|
318
|
+
${PASSTHRU[@]+"${PASSTHRU[@]}"}
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
set -euo pipefail
|
|
65
65
|
|
|
66
66
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
67
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
67
68
|
HOOK_SRC="${SCRIPT_DIR}/hook.sh"
|
|
68
69
|
HOOKS_TEMPLATE="${SCRIPT_DIR}/hooks.json"
|
|
69
70
|
|
|
@@ -177,7 +178,8 @@ done
|
|
|
177
178
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
178
179
|
subconscious/glm-5.2
|
|
179
180
|
subconscious/tim-qwen3.6-27b
|
|
180
|
-
subconscious/deepseek-v4-flash-marathon
|
|
181
|
+
subconscious/deepseek-v4-flash-marathon
|
|
182
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
181
183
|
SUPPORTED_MODELS=()
|
|
182
184
|
|
|
183
185
|
add_supported_model() {
|
|
@@ -294,13 +296,16 @@ write_config() {
|
|
|
294
296
|
local existing
|
|
295
297
|
existing="$(strip_subconscious "$models_json")"
|
|
296
298
|
|
|
297
|
-
local provider_models='[]' model_id
|
|
299
|
+
local provider_models='[]' model_id vision
|
|
298
300
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
301
|
+
vision=false
|
|
302
|
+
if subc_model_supports_vision "$model_id"; then vision=true; fi
|
|
299
303
|
provider_models=$(jq -cn \
|
|
300
304
|
--argjson models "$provider_models" \
|
|
301
305
|
--arg modelId "$model_id" \
|
|
302
306
|
--arg modelName "Subconscious ${model_id}" \
|
|
303
307
|
--arg url "$messages_url" \
|
|
308
|
+
--argjson vision "$vision" \
|
|
304
309
|
--argjson maxIn "$MAX_INPUT_TOKENS" \
|
|
305
310
|
--argjson maxOut "$MAX_OUTPUT_TOKENS" \
|
|
306
311
|
'$models + [{
|
|
@@ -308,7 +313,7 @@ write_config() {
|
|
|
308
313
|
name: $modelName,
|
|
309
314
|
url: $url,
|
|
310
315
|
toolCalling: true,
|
|
311
|
-
vision:
|
|
316
|
+
vision: $vision,
|
|
312
317
|
maxInputTokens: $maxIn,
|
|
313
318
|
maxOutputTokens: $maxOut,
|
|
314
319
|
thinking: true,
|
|
@@ -59,7 +59,8 @@ COMMAND="install"
|
|
|
59
59
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
60
60
|
subconscious/glm-5.2
|
|
61
61
|
subconscious/tim-qwen3.6-27b
|
|
62
|
-
subconscious/deepseek-v4-flash-marathon
|
|
62
|
+
subconscious/deepseek-v4-flash-marathon
|
|
63
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
63
64
|
|
|
64
65
|
SUPPORTED_MODELS=()
|
|
65
66
|
add_supported_model() {
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
set -euo pipefail
|
|
6
6
|
|
|
7
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
8
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
9
|
+
|
|
7
10
|
GATEWAY_URL="${GATEWAY_URL:-}"
|
|
8
11
|
API_KEY="${DEEPSEEK_HARNESS_API_KEY:-${API_KEY:-}}"
|
|
9
12
|
MODEL="${MODEL:-subconscious/glm-5.3-marathon}"
|
|
@@ -13,7 +16,8 @@ MAX_TOKENS="${DEEPSEEK_HARNESS_MAX_TOKENS:-65536}"
|
|
|
13
16
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
14
17
|
subconscious/glm-5.2
|
|
15
18
|
subconscious/tim-qwen3.6-27b
|
|
16
|
-
subconscious/deepseek-v4-flash-marathon
|
|
19
|
+
subconscious/deepseek-v4-flash-marathon
|
|
20
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
17
21
|
|
|
18
22
|
if [[ -z "$GATEWAY_URL" || -z "$API_KEY" ]]; then
|
|
19
23
|
echo "error: GATEWAY_URL and API_KEY are required to launch DeepSeek Harness" >&2
|
|
@@ -79,6 +83,9 @@ trap cleanup EXIT HUP INT TERM
|
|
|
79
83
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
80
84
|
printf " - id: '%s'\n" "$model_id"
|
|
81
85
|
printf " name: '%s'\n" "$model_id"
|
|
86
|
+
if subc_model_supports_vision "$model_id"; then
|
|
87
|
+
printf '%s\n' ' input: [text, image]'
|
|
88
|
+
fi
|
|
82
89
|
printf " contextWindow: %s\n" "$CONTEXT_WINDOW"
|
|
83
90
|
printf " maxTokens: %s\n" "$MAX_TOKENS"
|
|
84
91
|
done
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Generated from agents/registry.json. Do not edit by hand.
|
|
3
|
+
# Exact IDs only: similarly named models do not inherit capabilities.
|
|
4
|
+
subc_model_supports_vision() {
|
|
5
|
+
case "${1:-}" in
|
|
6
|
+
'subconscious/deepseek-v4.1-flash-marathon') return 0 ;;
|
|
7
|
+
*) return 1 ;;
|
|
8
|
+
esac
|
|
9
|
+
}
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
set -euo pipefail
|
|
55
55
|
|
|
56
56
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
57
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
57
58
|
|
|
58
59
|
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
59
60
|
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
@@ -122,7 +123,8 @@ done
|
|
|
122
123
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
123
124
|
subconscious/glm-5.2
|
|
124
125
|
subconscious/tim-qwen3.6-27b
|
|
125
|
-
subconscious/deepseek-v4-flash-marathon
|
|
126
|
+
subconscious/deepseek-v4-flash-marathon
|
|
127
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
126
128
|
SUPPORTED_MODELS=()
|
|
127
129
|
|
|
128
130
|
add_supported_model() {
|
|
@@ -147,7 +149,11 @@ done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
|
147
149
|
|
|
148
150
|
MODELS_JSON=""
|
|
149
151
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
150
|
-
|
|
152
|
+
vision_fields=""
|
|
153
|
+
if subc_model_supports_vision "$model_id"; then
|
|
154
|
+
vision_fields=',"attachment":true,"modalities":{"input":["text","image"],"output":["text"]}'
|
|
155
|
+
fi
|
|
156
|
+
model_json="\"${model_id}\":{\"name\":\"${model_id}\",\"tools\":true,\"limit\":{\"context\":${CONTEXT_LIMIT},\"output\":${OUTPUT_LIMIT}}${vision_fields}}"
|
|
151
157
|
if [[ -n "$MODELS_JSON" ]]; then
|
|
152
158
|
MODELS_JSON="${MODELS_JSON},${model_json}"
|
|
153
159
|
else
|
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
set -euo pipefail
|
|
19
19
|
|
|
20
20
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
21
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
21
22
|
|
|
22
23
|
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
23
24
|
SHARED_ENV="${SUBC_ENV_FILE:-${SCRIPT_DIR}/../.env}"
|
|
@@ -33,7 +34,8 @@ OUTPUT_LIMIT="${OPENCODE_OUTPUT_LIMIT:-65536}"
|
|
|
33
34
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
34
35
|
subconscious/glm-5.2
|
|
35
36
|
subconscious/tim-qwen3.6-27b
|
|
36
|
-
subconscious/deepseek-v4-flash-marathon
|
|
37
|
+
subconscious/deepseek-v4-flash-marathon
|
|
38
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
37
39
|
SUPPORTED_MODELS=()
|
|
38
40
|
|
|
39
41
|
add_supported_model() {
|
|
@@ -58,7 +60,11 @@ done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
|
58
60
|
|
|
59
61
|
MODELS_JSON=""
|
|
60
62
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
61
|
-
|
|
63
|
+
vision_fields=""
|
|
64
|
+
if subc_model_supports_vision "$model_id"; then
|
|
65
|
+
vision_fields=',"attachment":true,"modalities":{"input":["text","image"],"output":["text"]}'
|
|
66
|
+
fi
|
|
67
|
+
model_json="\"${model_id}\":{\"name\":\"${model_id}\",\"tools\":true,\"limit\":{\"context\":${CONTEXT_LIMIT},\"output\":${OUTPUT_LIMIT}}${vision_fields}}"
|
|
62
68
|
if [[ -n "$MODELS_JSON" ]]; then
|
|
63
69
|
MODELS_JSON="${MODELS_JSON},${model_json}"
|
|
64
70
|
else
|
|
@@ -47,6 +47,7 @@
|
|
|
47
47
|
set -euo pipefail
|
|
48
48
|
|
|
49
49
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
50
|
+
source "${SCRIPT_DIR}/../model-capabilities.generated.sh"
|
|
50
51
|
EXTENSION_SRC="${SCRIPT_DIR}/subconscious-compaction.ts"
|
|
51
52
|
|
|
52
53
|
# Load shared env from SUBC_ENV_FILE, or a sibling .env / env.example.
|
|
@@ -117,7 +118,8 @@ done
|
|
|
117
118
|
DEFAULT_SUBCONSCIOUS_MODELS="subconscious/glm-5.3-marathon
|
|
118
119
|
subconscious/glm-5.2
|
|
119
120
|
subconscious/tim-qwen3.6-27b
|
|
120
|
-
subconscious/deepseek-v4-flash-marathon
|
|
121
|
+
subconscious/deepseek-v4-flash-marathon
|
|
122
|
+
subconscious/deepseek-v4.1-flash-marathon"
|
|
121
123
|
SUPPORTED_MODELS=()
|
|
122
124
|
|
|
123
125
|
add_supported_model() {
|
|
@@ -142,7 +144,11 @@ done <<< "${SUBCONSCIOUS_MODELS:-$DEFAULT_SUBCONSCIOUS_MODELS}"
|
|
|
142
144
|
|
|
143
145
|
MODEL_ENTRIES_JSON=""
|
|
144
146
|
for model_id in "${SUPPORTED_MODELS[@]}"; do
|
|
145
|
-
|
|
147
|
+
vision_fields=""
|
|
148
|
+
if subc_model_supports_vision "$model_id"; then
|
|
149
|
+
vision_fields=',"input":["text","image"]'
|
|
150
|
+
fi
|
|
151
|
+
model_json="{\"id\":\"${model_id}\",\"contextWindow\":${CONTEXT_WINDOW},\"maxTokens\":${MAX_TOKENS},\"compat\":{\"sendSessionAffinityHeaders\":true,\"sessionAffinityFormat\":\"openai-nosession\"}${vision_fields}}"
|
|
146
152
|
if [[ -n "$MODEL_ENTRIES_JSON" ]]; then
|
|
147
153
|
MODEL_ENTRIES_JSON="${MODEL_ENTRIES_JSON},${model_json}"
|
|
148
154
|
else
|
package/bin/windows/launch.js
CHANGED
|
@@ -3,6 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { claudeNativeLaunch } from './claude.js';
|
|
6
|
+
import { modelSupportsVision } from '../model-capabilities.js';
|
|
6
7
|
import { defaults, value, origin, modelIds, positiveInteger, parseOptions, writeJson } from './common.js';
|
|
7
8
|
|
|
8
9
|
function connection(env, keyName) {
|
|
@@ -25,7 +26,10 @@ export async function windowsLaunch(id, argv, env, { tempRoot = os.tmpdir() } =
|
|
|
25
26
|
if (id === 'opencode') {
|
|
26
27
|
const context = positiveInteger(value(env, 'OPENCODE_CONTEXT_LIMIT', '5000000'), 'OPENCODE_CONTEXT_LIMIT');
|
|
27
28
|
const output = positiveInteger(value(env, 'OPENCODE_OUTPUT_LIMIT', '65536'), 'OPENCODE_OUTPUT_LIMIT');
|
|
28
|
-
const models = Object.fromEntries(modelIds(env).map(id => [id, {
|
|
29
|
+
const models = Object.fromEntries(modelIds(env).map(id => [id, {
|
|
30
|
+
name: id, tools: true, limit: { context, output },
|
|
31
|
+
...(modelSupportsVision(id) ? { attachment: true, modalities: { input: ['text', 'image'], output: ['text'] } } : {}),
|
|
32
|
+
}]));
|
|
29
33
|
childEnv.OPENCODE_CONFIG_CONTENT = JSON.stringify({
|
|
30
34
|
$schema: 'https://opencode.ai/config.json', disabled_providers: ['subconscious'],
|
|
31
35
|
provider: { 'subconscious-cli': { npm: '@ai-sdk/openai-compatible', name: 'Subconscious Gateway', options: {
|
|
@@ -51,6 +55,7 @@ export async function windowsLaunch(id, argv, env, { tempRoot = os.tmpdir() } =
|
|
|
51
55
|
supports_reasoning_summaries: false, support_verbosity: false, default_verbosity: null,
|
|
52
56
|
apply_patch_tool_type: 'freeform', truncation_policy: { mode: 'tokens', limit: 10000 },
|
|
53
57
|
supports_parallel_tool_calls: true, experimental_supported_tools: [],
|
|
58
|
+
...(modelSupportsVision(id) ? { input_modalities: ['text', 'image'] } : {}),
|
|
54
59
|
})) };
|
|
55
60
|
// Validate all flags before creating a temporary directory.
|
|
56
61
|
const threads = positiveInteger(value(env, 'MAX_CONCURRENT_SUBAGENTS', '4'), 'MAX_CONCURRENT_SUBAGENTS');
|
|
@@ -81,7 +86,7 @@ export async function windowsLaunch(id, argv, env, { tempRoot = os.tmpdir() } =
|
|
|
81
86
|
const cleanup = () => fs.rm(dir, { recursive: true, force: true });
|
|
82
87
|
try {
|
|
83
88
|
const file = path.join(dir, 'subconscious.cordis.yml');
|
|
84
|
-
const text = `- id: llm-pi-ai\n config:\n providers:\n subconscious:\n apiKeyEnv: SUBCONSCIOUS_API_KEY\n displayName: Subconscious Gateway\n api: openai-completions\n baseURL: !!js process.env.SUBCONSCIOUS_DSH_BASE_URL\n headers:\n x-subconscious-client: deepseek-harness\n compat:\n supportsDeveloperRole: false\n maxTokensField: max_tokens\n defaultContextWindow: ${context}\n defaultMaxTokens: ${maxTokens}\n models:\n${models.map(id => ` - id: '${id}'\n name: '${id}'\n contextWindow: ${context}\n maxTokens: ${maxTokens}`).join('\n')}\n- id: agent-default-model\n config:\n provider: subconscious\n model: '${model}'\n`;
|
|
89
|
+
const text = `- id: llm-pi-ai\n config:\n providers:\n subconscious:\n apiKeyEnv: SUBCONSCIOUS_API_KEY\n displayName: Subconscious Gateway\n api: openai-completions\n baseURL: !!js process.env.SUBCONSCIOUS_DSH_BASE_URL\n headers:\n x-subconscious-client: deepseek-harness\n compat:\n supportsDeveloperRole: false\n maxTokensField: max_tokens\n defaultContextWindow: ${context}\n defaultMaxTokens: ${maxTokens}\n models:\n${models.map(id => ` - id: '${id}'\n name: '${id}'\n${modelSupportsVision(id) ? ' input: [text, image]\n' : ''} contextWindow: ${context}\n maxTokens: ${maxTokens}`).join('\n')}\n- id: agent-default-model\n config:\n provider: subconscious\n model: '${model}'\n`;
|
|
85
90
|
await fs.writeFile(file, text, { mode: 0o600, flag: 'wx' });
|
|
86
91
|
const mode = ['web', 'headless'].includes(argv[0]) ? argv[0] : 'web';
|
|
87
92
|
const rest = ['web', 'headless'].includes(argv[0]) ? argv.slice(1) : argv;
|
package/bin/windows/setup.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { modelSupportsVision } from '../model-capabilities.js';
|
|
4
5
|
import { defaults, origin, value, modelIds, positiveInteger, parseOptions, object, readJson, writeJson } from './common.js';
|
|
5
6
|
|
|
6
7
|
const owned = command => {
|
|
@@ -92,7 +93,7 @@ export async function windowsSetup(id, action, argv, environment, { home = os.ho
|
|
|
92
93
|
const context = positiveInteger(options['--max-input-tokens'] || value(env, 'COPILOT_MAX_INPUT_TOKENS', '5000000'), 'max-input-tokens');
|
|
93
94
|
const maxTokens = positiveInteger(options['--max-output-tokens'] || value(env, 'COPILOT_MAX_OUTPUT_TOKENS', '65536'), 'max-output-tokens');
|
|
94
95
|
providers.push({ name: providerName, vendor: 'customendpoint', apiKey: '${input:chat.lm.secret.subconscious-gateway}', apiType: 'messages', models: modelIds(env).map(id => ({
|
|
95
|
-
id, name: `Subconscious ${id}`, url: `${gatewayUrl}/v1/messages`, toolCalling: true, vision:
|
|
96
|
+
id, name: `Subconscious ${id}`, url: `${gatewayUrl}/v1/messages`, toolCalling: true, vision: modelSupportsVision(id),
|
|
96
97
|
maxInputTokens: context, maxOutputTokens: maxTokens, thinking: true, streaming: true,
|
|
97
98
|
requestHeaders: { 'x-subconscious-client': 'copilot' },
|
|
98
99
|
})) });
|
|
@@ -131,7 +132,10 @@ export async function windowsSetup(id, action, argv, environment, { home = os.ho
|
|
|
131
132
|
if (installing) {
|
|
132
133
|
const context = positiveInteger(options['--context-window'] || value(env, 'PI_CONTEXT_WINDOW', '5000000'), 'context-window');
|
|
133
134
|
const maxTokens = positiveInteger(options['--max-tokens'] || value(env, 'PI_MAX_TOKENS', '65536'), 'max-tokens');
|
|
134
|
-
providers.subconscious = { baseUrl: `${gatewayUrl}/v1`, api: 'openai-completions', apiKey, headers: { 'x-subconscious-client': 'pi' }, models: modelIds(env).map(id => ({
|
|
135
|
+
providers.subconscious = { baseUrl: `${gatewayUrl}/v1`, api: 'openai-completions', apiKey, headers: { 'x-subconscious-client': 'pi' }, models: modelIds(env).map(id => ({
|
|
136
|
+
id, contextWindow: context, maxTokens, compat: { sendSessionAffinityHeaders: true, sessionAffinityFormat: 'openai-nosession' },
|
|
137
|
+
...(modelSupportsVision(id) ? { input: ['text', 'image'] } : {}),
|
|
138
|
+
})) };
|
|
135
139
|
await fs.mkdir(path.dirname(extension), { recursive: true });
|
|
136
140
|
await fs.copyFile(new URL('./pi-compaction.ts', import.meta.url), extension);
|
|
137
141
|
await writeJson(config, { gatewayUrl, apiKey });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subconscious-cli",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.4",
|
|
4
4
|
"description": "CLI for Subconscious — run Subconscious Code, Claude Code, Codex, OpenCode, DeepSeek Harness, Cursor, Copilot, and Pi",
|
|
5
5
|
"bin": {
|
|
6
6
|
"subc": "bin/cli.js"
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"build:tui": "node scripts/build-tui.js",
|
|
10
10
|
"build:tui:host": "node scripts/build-tui.js --host",
|
|
11
11
|
"test": "node --test",
|
|
12
|
-
"test:windows": "node --test test/windows.test.js test/models.test.js test/auth.test.js test/tui.test.js test/update-check.test.js test/sessions.test.js test/branding.test.js test/claude-version.test.js test/usage.test.js test/release.test.js",
|
|
12
|
+
"test:windows": "node --test test/windows.test.js test/models.test.js test/model-capabilities.test.js test/auth.test.js test/tui.test.js test/update-check.test.js test/sessions.test.js test/branding.test.js test/claude-version.test.js test/usage.test.js test/release.test.js",
|
|
13
13
|
"test:tui": "go -C tui test ./...",
|
|
14
14
|
"prepack": "npm run build:tui",
|
|
15
15
|
"prepublishOnly": "node scripts/require-publish-script.js"
|