super-dsh 0.1.6 → 0.1.10
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 +25 -3
- package/agent-agy/cordis.patch.yml +7 -4
- package/agent-agy/dist/agent.d.ts +12 -11
- package/agent-agy/dist/agy-auth-gateway.d.ts +124 -0
- package/agent-agy/dist/agy-auth-gateway.js +233 -0
- package/agent-agy/dist/agy-auth.d.ts +153 -0
- package/agent-agy/dist/agy-auth.js +179 -0
- package/agent-agy/dist/agy-cli-client.d.ts +39 -9
- package/agent-agy/dist/agy-cli-client.js +82 -18
- package/agent-agy/dist/agy-store.d.ts +8 -0
- package/agent-agy/dist/index.d.ts +46 -16
- package/agent-agy/dist/index.js +82 -56
- package/agent-agy/dist/models.d.ts +70 -0
- package/agent-agy/dist/models.js +102 -3
- package/agent-agy/package.json +7 -5
- package/agent-agy-sdk/cordis.patch.yml +58 -0
- package/agent-agy-sdk/dist/adapter.d.ts +15 -0
- package/agent-agy-sdk/dist/adapter.js +42 -0
- package/agent-agy-sdk/dist/agent-preset-agy.d.ts +27 -0
- package/agent-agy-sdk/dist/agent-preset-agy.js +32 -0
- package/agent-agy-sdk/dist/agent.d.ts +138 -0
- package/agent-agy-sdk/dist/agent.js +494 -0
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.d.ts +26 -6
- package/{agent-agy → agent-agy-sdk}/dist/agy-client.js +43 -25
- package/agent-agy-sdk/dist/agy-sessions.d.ts +25 -0
- package/agent-agy-sdk/dist/agy-sessions.js +107 -0
- package/agent-agy-sdk/dist/agy-store.d.ts +39 -0
- package/agent-agy-sdk/dist/agy-store.js +83 -0
- package/agent-agy-sdk/dist/inbox.d.ts +26 -0
- package/agent-agy-sdk/dist/inbox.js +53 -0
- package/agent-agy-sdk/dist/index.d.ts +93 -0
- package/agent-agy-sdk/dist/index.js +476 -0
- package/agent-agy-sdk/dist/models.d.ts +41 -0
- package/agent-agy-sdk/dist/models.js +74 -0
- package/agent-agy-sdk/dist/sdk-venv.d.ts +76 -0
- package/agent-agy-sdk/dist/sdk-venv.js +173 -0
- package/agent-agy-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-agy-sdk/dist/world-plugin.js +82 -0
- package/agent-agy-sdk/package.json +64 -0
- package/agent-codex/README.md +141 -36
- package/agent-codex/cordis.patch.yml +14 -10
- package/agent-codex/dist/adapter.js +64 -28
- package/agent-codex/dist/agent.js +255 -81
- package/agent-codex/dist/app-server-approvals.js +165 -0
- package/agent-codex/dist/app-server-client.js +723 -0
- package/agent-codex/dist/app-server-events.js +432 -0
- package/agent-codex/dist/app-server-protocol.js +95 -0
- package/agent-codex/dist/app-server-wire.js +299 -0
- package/agent-codex/dist/codex-launch.js +78 -0
- package/agent-codex/dist/codex-native-config.js +392 -0
- package/agent-codex/dist/codex-provider-gateway.js +402 -0
- package/agent-codex/dist/codex-providers.js +376 -0
- package/agent-codex/dist/codex-route.js +86 -0
- package/agent-codex/dist/index.js +256 -115
- package/agent-codex/dist/permission.js +75 -1
- package/agent-codex/package.json +1 -2
- package/agent-codex-sdk/README.md +79 -0
- package/agent-codex-sdk/cordis.patch.yml +81 -0
- package/agent-codex-sdk/dist/adapter.js +91 -0
- package/agent-codex-sdk/dist/agent-preset-codex.js +32 -0
- package/agent-codex-sdk/dist/agent.js +1085 -0
- package/agent-codex-sdk/dist/codex-native-config.js +392 -0
- package/agent-codex-sdk/dist/codex-provider-gateway.js +402 -0
- package/agent-codex-sdk/dist/codex-providers.js +376 -0
- package/agent-codex-sdk/dist/codex-route.js +86 -0
- package/{agent-codex/dist/codex-client.js → agent-codex-sdk/dist/codex-sdk-client.js} +253 -32
- package/agent-codex-sdk/dist/codex-sdk-launch.js +92 -0
- package/agent-codex-sdk/dist/codex-store.js +180 -0
- package/agent-codex-sdk/dist/inbox.js +53 -0
- package/agent-codex-sdk/dist/index.js +739 -0
- package/agent-codex-sdk/dist/permission.js +71 -0
- package/agent-codex-sdk/dist/sdk-runtime.js +307 -0
- package/agent-codex-sdk/dist/session-map.js +167 -0
- package/agent-codex-sdk/dist/world-plugin.js +93 -0
- package/agent-codex-sdk/package.json +79 -0
- package/agent-codex-sdk/scripts/fetch-sdk-runtime.mjs +57 -0
- package/agent-omp/README.md +72 -55
- package/agent-omp/dist/agent.js +36 -11
- package/agent-omp/dist/index.js +92 -52
- package/agent-omp/dist/lazy-rpc.js +11 -4
- package/agent-omp/dist/omp-cli.js +114 -97
- package/agent-omp/dist/omp-store.js +12 -4
- package/agent-omp/dist/permission.js +70 -5
- package/agent-omp/dist/rpc-client.js +409 -0
- package/agent-omp/dist/world-plugin.js +36 -3
- package/agent-omp/package.json +2 -6
- package/agent-omp-sdk/README.md +103 -0
- package/agent-omp-sdk/cordis.patch.yml +108 -0
- package/agent-omp-sdk/dist/adapter.d.ts +21 -0
- package/agent-omp-sdk/dist/adapter.js +36 -0
- package/agent-omp-sdk/dist/agent-preset-omp.d.ts +31 -0
- package/agent-omp-sdk/dist/agent-preset-omp.js +32 -0
- package/agent-omp-sdk/dist/agent.d.ts +64 -0
- package/agent-omp-sdk/dist/agent.js +1178 -0
- package/agent-omp-sdk/dist/discovery.d.ts +57 -0
- package/agent-omp-sdk/dist/discovery.js +116 -0
- package/agent-omp-sdk/dist/inbox.d.ts +28 -0
- package/agent-omp-sdk/dist/inbox.js +53 -0
- package/agent-omp-sdk/dist/index.d.ts +60 -0
- package/agent-omp-sdk/dist/index.js +632 -0
- package/agent-omp-sdk/dist/knobs.d.ts +34 -0
- package/agent-omp-sdk/dist/knobs.js +50 -0
- package/agent-omp-sdk/dist/lazy-rpc.d.ts +98 -0
- package/agent-omp-sdk/dist/lazy-rpc.js +178 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.d.ts +187 -0
- package/agent-omp-sdk/dist/mobile/zoom-guard.js +294 -0
- package/agent-omp-sdk/dist/mobile-boot.d.ts +49 -0
- package/agent-omp-sdk/dist/mobile-boot.js +38 -0
- package/agent-omp-sdk/dist/models.d.ts +39 -0
- package/agent-omp-sdk/dist/models.js +299 -0
- package/agent-omp-sdk/dist/omp-cli.d.ts +67 -0
- package/agent-omp-sdk/dist/omp-cli.js +164 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.d.ts +27 -0
- package/agent-omp-sdk/dist/omp-disk-discovery.js +178 -0
- package/agent-omp-sdk/dist/omp-executable.d.ts +2 -0
- package/agent-omp-sdk/dist/omp-executable.js +30 -0
- package/agent-omp-sdk/dist/omp-store.d.ts +134 -0
- package/agent-omp-sdk/dist/omp-store.js +526 -0
- package/agent-omp-sdk/dist/pairing.d.ts +7 -0
- package/agent-omp-sdk/dist/pairing.js +45 -0
- package/agent-omp-sdk/dist/permission.d.ts +138 -0
- package/agent-omp-sdk/dist/permission.js +161 -0
- package/agent-omp-sdk/dist/protocol.d.ts +189 -0
- package/agent-omp-sdk/dist/rpc-types.d.ts +77 -0
- package/agent-omp-sdk/dist/rpc-types.js +1 -0
- package/agent-omp-sdk/dist/sdk-client.d.ts +160 -0
- package/{agent-omp → agent-omp-sdk}/dist/sdk-client.js +108 -56
- package/agent-omp-sdk/dist/sdk-runtime.d.ts +211 -0
- package/agent-omp-sdk/dist/sdk-runtime.js +418 -0
- package/agent-omp-sdk/dist/sidecar-client.d.ts +87 -0
- package/agent-omp-sdk/dist/sidecar-client.js +197 -0
- package/agent-omp-sdk/dist/store/adapter.d.ts +17 -0
- package/agent-omp-sdk/dist/store/adapter.js +47 -0
- package/agent-omp-sdk/dist/store/db.d.ts +70 -0
- package/agent-omp-sdk/dist/store/db.js +210 -0
- package/agent-omp-sdk/dist/store/index.d.ts +23 -0
- package/agent-omp-sdk/dist/store/index.js +59 -0
- package/agent-omp-sdk/dist/store/reconcile.d.ts +15 -0
- package/agent-omp-sdk/dist/store/reconcile.js +51 -0
- package/agent-omp-sdk/dist/store/schema.d.ts +8 -0
- package/agent-omp-sdk/dist/store/schema.js +40 -0
- package/agent-omp-sdk/dist/transport.d.ts +49 -0
- package/agent-omp-sdk/dist/transport.js +35 -0
- package/agent-omp-sdk/dist/world-home.d.ts +4 -0
- package/agent-omp-sdk/dist/world-home.js +23 -0
- package/agent-omp-sdk/dist/world-plugin.d.ts +10 -0
- package/agent-omp-sdk/dist/world-plugin.js +137 -0
- package/agent-omp-sdk/package.json +87 -0
- package/client/index.js +1794 -287
- package/cordis.patch.yml +80 -0
- package/package.json +23 -8
- package/superd-hub/dist/a2a-delivery.d.ts +189 -0
- package/superd-hub/dist/a2a-delivery.js +240 -0
- package/superd-hub/dist/a2a-host.d.ts +76 -0
- package/superd-hub/dist/a2a-host.js +145 -0
- package/superd-hub/dist/a2a-ingest.d.ts +31 -0
- package/superd-hub/dist/a2a-ingest.js +636 -0
- package/superd-hub/dist/a2a-log.d.ts +17 -0
- package/superd-hub/dist/a2a-log.js +42 -0
- package/superd-hub/dist/a2a-row.d.ts +65 -0
- package/superd-hub/dist/a2a-row.js +162 -0
- package/superd-hub/dist/a2a-service.d.ts +357 -0
- package/superd-hub/dist/a2a-service.js +980 -0
- package/superd-hub/dist/a2a-wire.d.ts +220 -0
- package/superd-hub/dist/a2a-wire.js +305 -0
- package/superd-hub/dist/agent-ids.d.ts +10 -0
- package/superd-hub/dist/agent-ids.js +68 -0
- package/superd-hub/dist/agent-roster.d.ts +29 -18
- package/superd-hub/dist/agent-roster.js +54 -15
- package/superd-hub/dist/agent-status.d.ts +119 -0
- package/superd-hub/dist/agent-status.js +386 -0
- package/superd-hub/dist/client/agent-settings.d.ts +156 -0
- package/superd-hub/dist/client/agent-settings.js +229 -0
- package/superd-hub/dist/client/mesh-api.d.ts +134 -0
- package/superd-hub/dist/client/mesh-api.js +219 -0
- package/superd-hub/dist/client/mesh-groups.d.ts +63 -0
- package/superd-hub/dist/client/mesh-groups.js +66 -0
- package/superd-hub/dist/client/roster.d.ts +48 -0
- package/superd-hub/dist/client/roster.js +102 -0
- package/superd-hub/dist/client/runtime-settings-api.d.ts +76 -0
- package/superd-hub/dist/client/runtime-settings-api.js +137 -0
- package/superd-hub/dist/client/switch.d.ts +165 -0
- package/superd-hub/dist/client/switch.js +295 -0
- package/superd-hub/dist/exec-pty-channel.d.ts +58 -0
- package/superd-hub/dist/exec-pty-channel.js +162 -0
- package/superd-hub/dist/exec-pty-framing.d.ts +32 -0
- package/superd-hub/dist/exec-pty-framing.js +81 -0
- package/superd-hub/dist/exec-pty-rpc.d.ts +21 -0
- package/superd-hub/dist/exec-pty-rpc.js +128 -0
- package/superd-hub/dist/exec-pty-session.d.ts +76 -0
- package/superd-hub/dist/exec-pty-session.js +234 -0
- package/superd-hub/dist/exec.d.ts +56 -0
- package/superd-hub/dist/exec.js +225 -0
- package/superd-hub/dist/gateway.d.ts +39 -2
- package/superd-hub/dist/gateway.js +62 -3
- package/superd-hub/dist/hub-tool.d.ts +174 -0
- package/superd-hub/dist/hub-tool.js +464 -0
- package/superd-hub/dist/index.d.ts +15 -1
- package/superd-hub/dist/index.js +16 -0
- package/superd-hub/dist/machines.d.ts +45 -0
- package/superd-hub/dist/machines.js +125 -0
- package/superd-hub/dist/mesh-federate.d.ts +138 -0
- package/superd-hub/dist/mesh-federate.js +223 -0
- package/superd-hub/dist/mesh-gateway.d.ts +67 -0
- package/superd-hub/dist/mesh-gateway.js +408 -0
- package/superd-hub/dist/mesh-link.d.ts +274 -0
- package/superd-hub/dist/mesh-link.js +441 -0
- package/superd-hub/dist/mesh-rpc.d.ts +123 -0
- package/superd-hub/dist/mesh-rpc.js +250 -0
- package/superd-hub/dist/mux-client.d.ts +71 -0
- package/superd-hub/dist/mux-client.js +281 -0
- package/superd-hub/dist/pack-version.d.ts +2 -0
- package/superd-hub/dist/pack-version.js +30 -0
- package/superd-hub/dist/roster.d.ts +6 -0
- package/superd-hub/dist/rpc.d.ts +18 -2
- package/superd-hub/dist/rpc.js +34 -4
- package/superd-hub/dist/spawn-world.js +3 -1
- package/superd-hub/dist/switch-core.d.ts +62 -25
- package/superd-hub/dist/switch-core.js +53 -30
- package/superd-hub/dist/system-head.d.ts +22 -12
- package/superd-hub/dist/system-head.js +100 -84
- package/superd-hub/dist/wire-endpoints.d.ts +264 -0
- package/superd-hub/dist/wire-endpoints.js +180 -0
- package/superd-hub/lib/client/index.js +1794 -287
- package/superd-hub/package.json +11 -2
- package/agent-agy/dist/agent-preset-projection.d.ts +0 -31
- package/agent-agy/dist/agent-preset-projection.js +0 -33
- package/agent-claude/dist/agent-preset-projection.js +0 -30
- package/agent-codex/dist/agent-preset-projection.js +0 -37
- package/agent-codex/dist/app-home.js +0 -65
- package/agent-codex/dist/models.js +0 -152
- package/agent-codex/dist/spike.js +0 -46
- package/agent-hermes/dist/agent-preset-projection.js +0 -34
- package/agent-omp/dist/agent-preset-projection.js +0 -36
- package/agent-omp/dist/app-home.js +0 -86
- package/agent-omp/dist/sidecar-client.js +0 -195
- package/agent-pi/dist/agent-preset-projection.js +0 -29
- package/superd-hub/dist/client-shim.d.ts +0 -28
- package/superd-hub/dist/client-shim.js +0 -251
- package/superd-hub/dist/index-pass.d.ts +0 -22
- package/superd-hub/dist/index-pass.js +0 -47
- package/superd-hub/dist/labels.d.ts +0 -45
- package/superd-hub/dist/labels.js +0 -83
- /package/{agent-agy → agent-agy-sdk}/bridge/agy_bridge.py +0 -0
- /package/{agent-agy → agent-agy-sdk}/bridge/gemini_openai_server.mjs +0 -0
- /package/{agent-codex/dist/codex-events.js → agent-codex-sdk/dist/codex-sdk-events.js} +0 -0
- /package/{agent-omp → agent-omp-sdk}/dist/protocol.js +0 -0
- /package/{agent-omp → agent-omp-sdk}/sidecar/main.ts +0 -0
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* sdk-venv.ts — the lazy, durable Python venv the SDK bridge runs on.
|
|
3
|
+
*
|
|
4
|
+
* 2026-10-02 user ruling (spec §4.2): this package declares NO Python
|
|
5
|
+
* dependency and ships NO postinstall/allow-scripts hook. Nothing is fetched at
|
|
6
|
+
* install time; the FIRST real use fetches the venv into the world home, where
|
|
7
|
+
* it is durable across sessions, restarts and package upgrades. A second use
|
|
8
|
+
* reuses it (idempotent), and a FAILED fetch leaves a trace on disk instead of
|
|
9
|
+
* silently degrading into a confusing bridge crash.
|
|
10
|
+
*
|
|
11
|
+
* Why the world home rather than the package root: the package root is the
|
|
12
|
+
* installed tarball — read-only in every real consumer install, and shared by
|
|
13
|
+
* every world (the CLI one included). The world home is per-runtime, writable,
|
|
14
|
+
* and already the home of this adapter's own state.
|
|
15
|
+
*
|
|
16
|
+
* The bootstrap is two idempotent steps, so a half-built venv heals in place
|
|
17
|
+
* rather than being thrown away and re-downloaded:
|
|
18
|
+
* 1. `<worldHome>/sdk-venv/bin/python` missing → `python3 -m venv <dir>`
|
|
19
|
+
* 2. `<worldHome>/sdk-venv.json` marker missing → `pip install google-antigravity`
|
|
20
|
+
*/
|
|
21
|
+
import { execFileSync } from "node:child_process";
|
|
22
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
/** The Python distribution the bridge imports (`bridge/agy_bridge.py`). */
|
|
25
|
+
export const SDK_PYTHON_PACKAGE = "google-antigravity";
|
|
26
|
+
export function sdkVenvLayout(worldHome) {
|
|
27
|
+
const dir = join(worldHome, "sdk-venv");
|
|
28
|
+
return {
|
|
29
|
+
dir,
|
|
30
|
+
python: join(dir, "bin", "python"),
|
|
31
|
+
pip: join(dir, "bin", "pip"),
|
|
32
|
+
marker: join(worldHome, "sdk-venv.json"),
|
|
33
|
+
errorLog: join(worldHome, "sdk-venv.error.log"),
|
|
34
|
+
lock: join(worldHome, "sdk-venv.lock"),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** Read the install marker; undefined when absent or unreadable. */
|
|
38
|
+
export function readSdkVenvRecord(worldHome) {
|
|
39
|
+
const { marker } = sdkVenvLayout(worldHome);
|
|
40
|
+
if (!existsSync(marker))
|
|
41
|
+
return undefined;
|
|
42
|
+
try {
|
|
43
|
+
const parsed = JSON.parse(readFileSync(marker, "utf8"));
|
|
44
|
+
return typeof parsed === "object" && parsed !== null ? parsed : undefined;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Fast path: the complete venv already exists → the interpreter to use. */
|
|
51
|
+
export function resolveSdkPython(worldHome) {
|
|
52
|
+
const layout = sdkVenvLayout(worldHome);
|
|
53
|
+
return existsSync(layout.python) && existsSync(layout.marker) ? layout.python : undefined;
|
|
54
|
+
}
|
|
55
|
+
const DEFAULTS = {
|
|
56
|
+
basePython: "python3",
|
|
57
|
+
lockTimeoutMs: 30 * 60 * 1000,
|
|
58
|
+
lockPollMs: 1000,
|
|
59
|
+
lockStaleMs: 30 * 60 * 1000,
|
|
60
|
+
};
|
|
61
|
+
function defaultRun(cmd, args) {
|
|
62
|
+
execFileSync(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Return the interpreter path for `<worldHome>`'s durable venv, fetching it
|
|
66
|
+
* first when it is absent or incomplete.
|
|
67
|
+
*
|
|
68
|
+
* Idempotent: a complete venv short-circuits without touching the network.
|
|
69
|
+
* Failures append to `<worldHome>/sdk-venv.error.log` and throw a single
|
|
70
|
+
* actionable error — never a partial venv left behind a success marker.
|
|
71
|
+
*/
|
|
72
|
+
export async function ensureSdkVenv(worldHome, opts = {}) {
|
|
73
|
+
const layout = sdkVenvLayout(worldHome);
|
|
74
|
+
const now = opts.now ?? Date.now;
|
|
75
|
+
const sleep = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
76
|
+
const run = opts.run ?? defaultRun;
|
|
77
|
+
const ready = resolveSdkPython(worldHome);
|
|
78
|
+
if (ready !== undefined)
|
|
79
|
+
return ready;
|
|
80
|
+
mkdirSync(worldHome, { recursive: true });
|
|
81
|
+
// `acquired === false` means a peer finished the fetch while we waited: the
|
|
82
|
+
// lock is not ours and MUST NOT be released by this caller.
|
|
83
|
+
const acquired = await acquireLock(worldHome, layout, now, sleep, opts);
|
|
84
|
+
if (!acquired)
|
|
85
|
+
return layout.python;
|
|
86
|
+
try {
|
|
87
|
+
// Re-check inside the lock: a concurrent bootstrap may have finished while
|
|
88
|
+
// we waited, in which case this caller pays nothing.
|
|
89
|
+
const done = resolveSdkPython(worldHome);
|
|
90
|
+
if (done !== undefined)
|
|
91
|
+
return done;
|
|
92
|
+
const basePython = opts.basePython ?? process.env.AGY_SDK_BASE_PYTHON ?? DEFAULTS.basePython;
|
|
93
|
+
const stale = existsSync(layout.python);
|
|
94
|
+
try {
|
|
95
|
+
opts.trace?.(`sdk-venv: fetching ${SDK_PYTHON_PACKAGE} into ${layout.dir}`);
|
|
96
|
+
if (!stale)
|
|
97
|
+
run(basePython, ["-m", "venv", layout.dir]);
|
|
98
|
+
run(layout.pip, ["install", "-q", SDK_PYTHON_PACKAGE]);
|
|
99
|
+
if (!existsSync(layout.python)) {
|
|
100
|
+
throw new Error(`venv created but ${layout.python} is missing`);
|
|
101
|
+
}
|
|
102
|
+
const record = {
|
|
103
|
+
package: SDK_PYTHON_PACKAGE,
|
|
104
|
+
python: layout.python,
|
|
105
|
+
installedAt: new Date(now()).toISOString(),
|
|
106
|
+
createdWith: basePython,
|
|
107
|
+
};
|
|
108
|
+
writeFileSync(layout.marker, JSON.stringify(record, null, 2) + "\n");
|
|
109
|
+
rmSync(layout.errorLog, { force: true });
|
|
110
|
+
opts.trace?.(`sdk-venv: ready (${layout.python})`);
|
|
111
|
+
return layout.python;
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
115
|
+
const stamp = new Date(now()).toISOString();
|
|
116
|
+
try {
|
|
117
|
+
appendFileSync(layout.errorLog, `[${stamp}] ${SDK_PYTHON_PACKAGE} fetch failed: ${detail}\n`);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
/* the trace is best-effort; the throw below is the contract */
|
|
121
|
+
}
|
|
122
|
+
throw new Error(`agy-sdk: could not fetch the Python SDK venv (${SDK_PYTHON_PACKAGE}) at ${layout.dir}: ${detail}. ` +
|
|
123
|
+
`Install it by hand with \`npm run fetch-venv\` (or set AGY_PYTHON to an interpreter that has it). ` +
|
|
124
|
+
`Trace: ${layout.errorLog}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
rmSync(layout.lock, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* mkdir-based mutex with stale-lock reclamation.
|
|
133
|
+
*
|
|
134
|
+
* Resolves `true` when THIS caller owns the lock (and must release it), `false`
|
|
135
|
+
* when a peer completed the fetch while we waited (nothing to release, the
|
|
136
|
+
* venv is ready). Throws when the wait budget is exhausted.
|
|
137
|
+
*/
|
|
138
|
+
async function acquireLock(worldHome, layout, now, sleep, opts) {
|
|
139
|
+
const timeout = opts.lockTimeoutMs ?? DEFAULTS.lockTimeoutMs;
|
|
140
|
+
const poll = opts.lockPollMs ?? DEFAULTS.lockPollMs;
|
|
141
|
+
const staleMs = opts.lockStaleMs ?? DEFAULTS.lockStaleMs;
|
|
142
|
+
const deadline = now() + timeout;
|
|
143
|
+
for (;;) {
|
|
144
|
+
try {
|
|
145
|
+
mkdirSync(layout.lock);
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch (error) {
|
|
149
|
+
if (error.code !== "EEXIST")
|
|
150
|
+
throw error;
|
|
151
|
+
}
|
|
152
|
+
// Someone holds it. Another process may have finished the fetch already.
|
|
153
|
+
if (resolveSdkPython(worldHome) !== undefined)
|
|
154
|
+
return false;
|
|
155
|
+
let ageMs = 0;
|
|
156
|
+
try {
|
|
157
|
+
ageMs = now() - statSync(layout.lock).mtimeMs;
|
|
158
|
+
}
|
|
159
|
+
catch {
|
|
160
|
+
continue; // released between the mkdir attempt and the stat — retry now
|
|
161
|
+
}
|
|
162
|
+
if (ageMs > staleMs) {
|
|
163
|
+
opts.trace?.(`sdk-venv: stealing stale lock (age ${Math.round(ageMs / 1000)}s)`);
|
|
164
|
+
rmSync(layout.lock, { recursive: true, force: true });
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (now() >= deadline) {
|
|
168
|
+
throw new Error(`agy-sdk: timed out waiting for a concurrent SDK venv fetch (lock ${layout.lock}). ` +
|
|
169
|
+
`Remove the lock directory if no fetch is running.`);
|
|
170
|
+
}
|
|
171
|
+
await sleep(poll);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const name = "agent-agy-sdk";
|
|
2
|
+
/** Structural slice of the ctx0 services the mount needs. */
|
|
3
|
+
interface HostContext {
|
|
4
|
+
provide(name: string, value: unknown): void;
|
|
5
|
+
inject(deps: string[], callback: (ctx: unknown) => void): unknown;
|
|
6
|
+
effect?(callback: () => () => void, label?: string): unknown;
|
|
7
|
+
get(name: string): unknown;
|
|
8
|
+
}
|
|
9
|
+
export declare function apply(ctx: HostContext): void;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent-agy — the Antigravity (agy) adapter's WORLD plugin (spec S2):
|
|
3
|
+
* activation IS roster membership.
|
|
4
|
+
*
|
|
5
|
+
* AW-B data-plane shape (DL1–DL5 → path-separation T-D), mirroring
|
|
6
|
+
* `@pgmi-builds/agent-omp/world` and `@pgmi-builds/agent-codex/world` so the
|
|
7
|
+
* hub sees every foreign runtime through one shape: the world is spawned as a
|
|
8
|
+
* sibling ROOT context with NO listener and NO webui composition
|
|
9
|
+
* (`worldMountPatches`) — a pure data plane behind the hub's `/hub` family.
|
|
10
|
+
*
|
|
11
|
+
* 1. ctx0 publishes the host mount record (the world's addressability
|
|
12
|
+
* entry — no webServer, no fence: those legs retired with the world
|
|
13
|
+
* pages) before spawn;
|
|
14
|
+
* 2. the world's entry row provides the virtual `webServer` (a silent
|
|
15
|
+
* sink) plus the neutral `webRuntime` facts its connection row injects;
|
|
16
|
+
* 3. the hub's `/hub` family answers `?agent=agy` traffic in ctx0's auth
|
|
17
|
+
* domain and dispatches into this world's gateway instance (the
|
|
18
|
+
* per-label `/<label>/api` + `/<label>/api/remote.mux` mounts retired
|
|
19
|
+
* in T-C, `mountWorld` deleted in T-D).
|
|
20
|
+
*/
|
|
21
|
+
import { mkdirSync } from 'node:fs';
|
|
22
|
+
import { resolveDshHome } from '@deepseek-ai/dsh-home-paths';
|
|
23
|
+
import { join } from 'node:path';
|
|
24
|
+
import { spawnWorld, registerAgent, setReady, registerForeignTarget, registerHostMount, worldMountPatches, provisionWorldProfile, resolveInstallAnchor, } from '../../superd-hub/dist/index.js';
|
|
25
|
+
export const name = 'agent-agy-sdk';
|
|
26
|
+
/**
|
|
27
|
+
* Runtime key — also the mount label. Deliberately NOT `agy`: the hub's roster
|
|
28
|
+
* (registerAgent) hard-throws on a duplicate key, and this row ships alongside
|
|
29
|
+
* the CLI row in the same composite. Distinct keys keep both independently
|
|
30
|
+
* toggleable and make the "both enabled" mistake survivable.
|
|
31
|
+
*/
|
|
32
|
+
const KEY = 'agy-sdk';
|
|
33
|
+
export function apply(ctx) {
|
|
34
|
+
registerAgent({ key: KEY, label: 'Antigravity (SDK)', ready: false });
|
|
35
|
+
// Harness resolver (env → ~/.dsh): a consumer install has no DSH_HOME and
|
|
36
|
+
// no cwd contract — deriving the world root from cwd spawns worlds into a
|
|
37
|
+
// garbage tree or throws inside apply() and kills the whole host boot.
|
|
38
|
+
const root = resolveDshHome();
|
|
39
|
+
// Nested home: the world's DSH data lives INSIDE `agents/<label>` (sessions
|
|
40
|
+
// / settings / workspaces, and the adapter's dsh-sessions.json mapping).
|
|
41
|
+
// agy-sdk: the world home carries the DSH-side state AND the lazily fetched
|
|
42
|
+
// durable Python venv (sdk-venv.ts); nothing is nested for the SDK itself.
|
|
43
|
+
const worldHome = join(root, 'agents', KEY);
|
|
44
|
+
mkdirSync(join(worldHome, 'profiles'), { recursive: true });
|
|
45
|
+
// Publish story: a foreign install has no line bootstrap, so the nested
|
|
46
|
+
// profile + @pgmi-builds links are provisioned HERE (idempotent).
|
|
47
|
+
provisionWorldProfile({
|
|
48
|
+
key: KEY,
|
|
49
|
+
adapterPkg: '@pgmi-builds/agent-agy-sdk',
|
|
50
|
+
worldHome,
|
|
51
|
+
});
|
|
52
|
+
const world = (async () => {
|
|
53
|
+
// T-D: no ctx0 listening-stack wait — the mount record is addressability
|
|
54
|
+
// only and the /hub family wires its own gate in ctx0 (gateway.ts).
|
|
55
|
+
const dropHostMount = registerHostMount({ key: KEY, labelPath: `/${KEY}` });
|
|
56
|
+
const ctxW = await spawnWorld({
|
|
57
|
+
appName: `superd-${KEY}`,
|
|
58
|
+
profileName: 'web',
|
|
59
|
+
installAnchor: resolveInstallAnchor(ctx), // lazy: never at module scope — import must stay side-effect-free
|
|
60
|
+
home: worldHome,
|
|
61
|
+
dataHome: worldHome,
|
|
62
|
+
// The host's live table carries this world: spawnWorld republishes a
|
|
63
|
+
// widened successor before boot imports anything (spec §2.1), and
|
|
64
|
+
// @pgmi-builds rows resolve from the profile-local links written above.
|
|
65
|
+
host: ctx,
|
|
66
|
+
extraPatches: worldMountPatches(KEY),
|
|
67
|
+
});
|
|
68
|
+
const gateway = ctxW.get('typertGateway');
|
|
69
|
+
registerForeignTarget({ key: KEY, gateway });
|
|
70
|
+
setReady(KEY, true);
|
|
71
|
+
ctx.effect?.(() => () => {
|
|
72
|
+
dropHostMount();
|
|
73
|
+
}, `agent-${KEY}: mount`);
|
|
74
|
+
return ctxW;
|
|
75
|
+
})().catch((cause) => {
|
|
76
|
+
// A failed world degrades to a not-ready roster row; a rejected provided
|
|
77
|
+
// promise would fail the entire host boot (loader entry apply).
|
|
78
|
+
console.error(`[super-dsh] ${KEY} world failed:`, cause);
|
|
79
|
+
return null;
|
|
80
|
+
});
|
|
81
|
+
ctx.provide(`superd.world.${KEY}`, world);
|
|
82
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pgmi-builds/agent-agy-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Google Antigravity (Gemini) provider for DeepSeek Harness (dsh) — the OPT-IN SDK transport: drives the google-antigravity Python SDK through a JSONL stdio bridge (bridge/agy_bridge.py, localharness embedded). Auth: adapter-side/GEMINI_API_KEY key, else Vertex over ADC. The agy CLI is never invoked — that is @pgmi-builds/agent-agy. Delivered DISABLED by default (roster key `agy-sdk`): the CLI adapter is the primary path because it reuses the user's existing Antigravity environment. No Python dependency is declared anywhere and there is no postinstall/allow-scripts hook — the durable venv is fetched into the world home on first real use (src/sdk-venv.ts, `npm run fetch-venv`).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./dist/index.js",
|
|
8
|
+
"./world": "./dist/world-plugin.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"bridge",
|
|
13
|
+
"cordis.patch.yml"
|
|
14
|
+
],
|
|
15
|
+
"dsh": {
|
|
16
|
+
"bundle": {
|
|
17
|
+
"patch": "./cordis.patch.yml"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.json",
|
|
22
|
+
"test": "node --test test/*.test.mjs",
|
|
23
|
+
"fetch-venv": "node scripts/fetch-venv.mjs"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"zod": "3.25.76"
|
|
27
|
+
},
|
|
28
|
+
"peerDependencies": {
|
|
29
|
+
"@deepseek-ai/cordis": "^4.0.1",
|
|
30
|
+
"@deepseek-ai/dsh-agent": ">=0.1.5-0 <0.3.0-0",
|
|
31
|
+
"@deepseek-ai/dsh-llm": ">=0.1.5-0 <0.3.0-0",
|
|
32
|
+
"@deepseek-ai/dsh-scope": ">=0.1.5-0 <0.3.0-0",
|
|
33
|
+
"@deepseek-ai/dsh-session": ">=0.1.5-0 <0.3.0-0",
|
|
34
|
+
"@deepseek-ai/dsh-session-persistence": ">=0.1.5-0 <0.3.0-0"
|
|
35
|
+
},
|
|
36
|
+
"peerDependenciesMeta": {
|
|
37
|
+
"@deepseek-ai/cordis": {
|
|
38
|
+
"optional": true
|
|
39
|
+
},
|
|
40
|
+
"@deepseek-ai/dsh-agent": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"@deepseek-ai/dsh-llm": {
|
|
44
|
+
"optional": true
|
|
45
|
+
},
|
|
46
|
+
"@deepseek-ai/dsh-scope": {
|
|
47
|
+
"optional": true
|
|
48
|
+
},
|
|
49
|
+
"@deepseek-ai/dsh-session": {
|
|
50
|
+
"optional": true
|
|
51
|
+
},
|
|
52
|
+
"@deepseek-ai/dsh-session-persistence": {
|
|
53
|
+
"optional": true
|
|
54
|
+
}
|
|
55
|
+
},
|
|
56
|
+
"devDependencies": {
|
|
57
|
+
"@types/node": "^26.2.0",
|
|
58
|
+
"typescript": "^5.6.0"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public"
|
|
62
|
+
},
|
|
63
|
+
"main": "dist/index.js"
|
|
64
|
+
}
|
package/agent-codex/README.md
CHANGED
|
@@ -1,58 +1,92 @@
|
|
|
1
1
|
# @pgmi-builds/agent-codex
|
|
2
2
|
|
|
3
|
-
superd 外壳下的 **Codex adapter**(super-dsh
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
superd 外壳下的 **Codex adapter**(super-dsh 线):把 Codex CLI 经由 **`codex app-server`**
|
|
4
|
+
接进 DSH —— 会话、事件、模型目录、审批、持久化全部按 DSH 语义呈现,WebUI 消费的是 DSH
|
|
5
|
+
服务提供的数据面。
|
|
6
6
|
|
|
7
7
|
> 通用规则(定位 / 两形态 / 测试准则 / 接线域 / per-agent 定制权 / home 与 profile 布局)
|
|
8
8
|
> 见上级目录的 `agent-adapter-dev-rules.md` —— 改本包前先读它。
|
|
9
|
+
> 迁移计划与实证:`docs/superpowers/plans/2026-10-03-agent-codex-app-server-migration.md`。
|
|
9
10
|
|
|
10
11
|
## 它是什么
|
|
11
12
|
|
|
12
13
|
- 一个**普通 dsh plugin bundle**:`package.json` 的 `dsh.bundle.patch` 指向本目录的
|
|
13
14
|
`cordis.patch.yml`(挂 codex provider、关掉它替代的原生行、重写权限三档表、pin 应用内目录选择器)。
|
|
14
15
|
- 一个 **AgentFactory**:`src/index.ts` 里的 `CodexProvider` 在 `ctx.agents` 注册工厂,
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
- **不包含** 任何 hub 耦合:世界挂载由 hub
|
|
18
|
-
|
|
16
|
+
**每个会话一个 `codex app-server` 子进程**(`src/app-server-client.ts`);
|
|
17
|
+
`src/agent.ts` 把 app-server 通知流投影成 DSH 会话事件。
|
|
18
|
+
- **不包含** 任何 hub 耦合:世界挂载由 hub 侧驱动。本包自己就足以点亮一个完整的 web app。
|
|
19
|
+
|
|
20
|
+
## 线别(2026-10-03 迁移)
|
|
21
|
+
|
|
22
|
+
**app-server 线**取代了原 `@openai/codex-sdk` 线(SDK 依赖已从本包与主 pack 移除)。
|
|
23
|
+
SDK 线在 adapter 里登记的一整排降级被 app-server 协议面直接消掉:
|
|
24
|
+
|
|
25
|
+
| 能力 | SDK 线(已退役) | app-server 线(现役) |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| 打断 | 只有 AbortSignal(掐断本轮 stream) | **`turn/interrupt`** |
|
|
28
|
+
| steer | 无 → 排队 followUp 近似 | **`turn/steer`**(注入进行中的 turn) |
|
|
29
|
+
| 运行时换模型 | 无 → 下一轮 `resumeThread` | **`turn/start.model`**(下一轮起生效,线程不重建) |
|
|
30
|
+
| 运行时审批档 | 无 → launch-only 预设 | **`turn/start.approvalPolicy`**(折叠 `approval/policy`,`/permission` 可用) |
|
|
31
|
+
| 运行时沙箱档 | 无 → launch-only | **`turn/start.sandboxPolicy`**(折叠 `sandbox/mode`) |
|
|
32
|
+
| 审批人机回路 | 无(`sendRaw` 是 no-op) | **`*/requestApproval` → DSH `ctx.approval`**(Web UI ApprovalPanel) |
|
|
33
|
+
| 用户消息回显 | 无(SDK item 无 `user_message`) | `item/started userMessage` |
|
|
34
|
+
| token usage | 只在本轮 `turn/completed`,滞后 | `thread/tokenUsage/updated`(本轮 `turn_end` 附着) |
|
|
35
|
+
|
|
36
|
+
**未接(登记 backlog)**:`thread/compact/start`(`/compact` 仍显式拒绝)、
|
|
37
|
+
`thread/list` 会话清单(DSH 日志仍是权威)、`skills/list` / `mcpServerStatus/list` 面板、
|
|
38
|
+
`thread/fork`、`requestUserInput` / `mcpServer/elicitation`(fail-closed 应答)、
|
|
39
|
+
collab/subagent 项。
|
|
19
40
|
|
|
20
41
|
## 单独跑起来(首选开发/验收形态)
|
|
21
42
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
SUPERD_APP_PORT=4989 bash super-dsh/test/start-codex-app.sh
|
|
25
|
-
# 脚本会打印 loopback / LAN token URL;停止:
|
|
26
|
-
systemctl --user stop superd-codex-app-<port>-test superd-codex-app-<port>-relay
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
环境变量:`SUPERD_APP_PORT`(端口)、`SUPERD_APP_HOME`(默认 `$WT/.tests`)、
|
|
30
|
-
`SUPERD_LAN_HOST`(默认 `192.168.31.130`)、`CODEX_TRACE=1`(provider/agent 追踪)。
|
|
43
|
+
场景级验证唯一入口 = **整包 pack 线**(`super-dsh/test/start-4999.sh`)+ dev3 目标机实装
|
|
44
|
+
(2026-09-24「场景退役」裁决);本包不再有 standalone 启动脚本。
|
|
31
45
|
|
|
32
46
|
## Home 与 profile 布局(user 裁定)
|
|
33
47
|
|
|
34
48
|
| 位置 | 内容 |
|
|
35
49
|
|---|---|
|
|
36
50
|
| `$DSH_HOME`(测试 = `<repo>/.tests`) | 测试 DSH home |
|
|
37
|
-
|
|
|
38
|
-
| `$DSH_HOME/
|
|
39
|
-
| `$DSH_HOME/
|
|
40
|
-
|
|
41
|
-
**禁止**自造 per-app home(如 `.tests/codex-app`)。
|
|
51
|
+
| 原生 `~/.codex`(`CODEX_HOME` 才重定向) | **Codex 原生 app home**:`config.toml` / `auth.json` / 模型 catalog / rollout / state。adapter **绝不重定向**(红线 §5),**从不写入**(单向阀) |
|
|
52
|
+
| `$DSH_HOME/agents/codex` | 该 world 的 **DSH home**:DSH 会话日志副本、storages、`dsh-sessions.json` 映射 |
|
|
53
|
+
| `$DSH_HOME/profiles/superd-pub` | 整包线的 dsh profile(tarball 物理安装) |
|
|
42
54
|
|
|
43
55
|
## 关键实现点
|
|
44
56
|
|
|
45
|
-
- **
|
|
46
|
-
|
|
47
|
-
|
|
57
|
+
- **lazy spawn(硬门)**:`CodexAppServerClient.create()` 零 IO、零子进程;`ensureStarted()`
|
|
58
|
+
在**首个真实 prompt** 才 spawn + `initialize` + `thread/start|resume`。查看/创建/resume
|
|
59
|
+
一个会话不产生任何 native 进程。单测直接钉住这条不变量(transport factory 调用计数 = 0)。
|
|
60
|
+
- **进程回收**:子进程 `detached: true`(自有进程组),close 时先 `SIGTERM` 进程组、
|
|
61
|
+
宽限后 `SIGKILL`,再 `child.kill()` 兜底——stdio MCP 后代 `setsid` 逃离时仍能被扫到。
|
|
62
|
+
- **session 身份 = 一对一映射**:DSH session id 是权威;Codex thread id 在**线程 attach**
|
|
63
|
+
时经 `onThreadAttached` 写入 `<dshHome>/dsh-sessions.json`(`src/session-map.ts`)。
|
|
64
|
+
resume 只经该映射重挂线程,查不到即 fail-closed。
|
|
48
65
|
- **DSH-native 持久化**:工厂按上游 agent-loop 的方式持有写通道(create `persistence.create` /
|
|
49
66
|
resume `persistence.open(id,'write')` → `read` → `interruptedTurnClosers` → `prepare`),
|
|
50
67
|
发布点刷未存后缀,dispose 时 `handle.close()` 排空。
|
|
51
|
-
-
|
|
52
|
-
`installModelSelection
|
|
53
|
-
-
|
|
54
|
-
`
|
|
55
|
-
`
|
|
68
|
+
- **每会话路由钉住**:create/resume 时同步钉住本会话路由(追加 `model/selection` +
|
|
69
|
+
`installModelSelection`),**不依赖全局默认模型的落盘时序**。
|
|
70
|
+
- **每轮权限折叠**:`agent.ts` 在每次 `turn/start` 前把会话日志的
|
|
71
|
+
`approval/policy` / `sandbox/mode`(无则由 preset 表兜底)折成 codex 覆盖
|
|
72
|
+
(`permission.ts` 的 `turnPolicyFromEvents`);`CODEX_APPROVAL_MODE` 只覆盖审批半边。
|
|
73
|
+
- **审批桥 fail-closed**:`app-server-approvals.ts` 把 server-request 映射到
|
|
74
|
+
`ctx.approval.request()`;无 answerer / 抛错 / 超时(`CODEX_APPROVAL_TIMEOUT_MS`,默认 5 分钟)
|
|
75
|
+
一律 **decline**,绝不让 codex 挂死。
|
|
76
|
+
- **事件映射**:`system/message`(rollout HEAD `base_instructions`)、`request/context`、
|
|
77
|
+
`assistant/message`(reasoning 用 `{type:'reasoning',text}`)、
|
|
78
|
+
`tool/call`(原始 JSON 串)/`tool/result`、`step/start|end`、`turn/start|end`、`todo/write`。
|
|
79
|
+
|
|
80
|
+
## 环境变量
|
|
81
|
+
|
|
82
|
+
| 变量 | 作用 |
|
|
83
|
+
|---|---|
|
|
84
|
+
| `CODEX_TRACE=1` | provider/agent/app-server 追踪(stderr) |
|
|
85
|
+
| `CODEX_BIN` | 覆盖 codex 入口脚本(测试);默认 = 本包 pin 的 `@openai/codex/bin/codex.js` |
|
|
86
|
+
| `CODEX_HOME` | Codex 原生 home 重定向(**测试专用**;生产路径零重定向) |
|
|
87
|
+
| `CODEX_APPROVAL_MODE` | 覆盖审批档(`never`/`on-request`/`on-failure`/`untrusted`;非法值忽略) |
|
|
88
|
+
| `CODEX_APPROVAL_TIMEOUT_MS` | 审批应答超时;`0` 关闭;默认 300000 |
|
|
89
|
+
| `CODEX_IDLE_EXIT_MS` | 会话空闲后拆客户端;`0` 关闭;默认 600000 |
|
|
56
90
|
|
|
57
91
|
## 测试
|
|
58
92
|
|
|
@@ -63,12 +97,83 @@ SUPERD_DSH_ANCHOR=<repo>/upstream/deepseek-harness/package.json \
|
|
|
63
97
|
node --test test/*.test.mjs
|
|
64
98
|
```
|
|
65
99
|
|
|
66
|
-
|
|
100
|
+
单测全部是 fake:`test/fixtures/fake-app-server.mjs` 是一个**可编程的 app-server 替身**
|
|
101
|
+
(真 JSONL JSON-RPC 分帧、真子进程),wire / client 测试用真管道驱动它;投影器与审批桥是纯函数。
|
|
102
|
+
**不 spawn 真 codex、不打模型。**
|
|
103
|
+
|
|
104
|
+
## 已知边界(app-server 线 v1)
|
|
67
105
|
|
|
68
|
-
|
|
106
|
+
- `thread/compact/start` 未接 → `/compact` 仍以显式错误拒绝;
|
|
107
|
+
- 会话清单仍由 DSH 日志提供(不接 `thread/list`,遵守 mapping-only);
|
|
108
|
+
- `requestUserInput` / `mcpServer/elicitation` / `permissions/requestApproval` 一律 fail-closed;
|
|
109
|
+
- collab / subagent / `thread/fork` / skills / MCP 面板未接;
|
|
110
|
+
- 内存镜像 `getMessages()` 仅供诊断,权威转录是 DSH 会话日志。
|
|
69
111
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
112
|
+
## 多 provider 面(Hub + DSH,2026-10-04 重做)
|
|
113
|
+
|
|
114
|
+
Codex 是**单 provider** harness:它自己的 `config.toml` 只能写一个 `model_provider`。provider 的**清单**
|
|
115
|
+
在 Codex 家里无处安放——那正是 cc-switch 存在的理由;而「这个会话现在跑在哪个 provider 上」在 DSH
|
|
116
|
+
里已有公认答案(`session/selectModel` + 持久的 `model/selection`)。所以本线**只做清单**,选择交给 DSH:
|
|
117
|
+
|
|
118
|
+
- adapter 的 store 是**正本**(canonical),原生 `config.toml` 是**来源**(source),单向读入;
|
|
119
|
+
- UI 不再有「active provider」概念——界面里切换 provider/model 就是 DSH 自带模型选择器,与本仓其它
|
|
120
|
+
harness 完全一致;
|
|
121
|
+
- provider 由**进程参数**注入子进程(`-c model_providers.<id>.*`),**不写任何原生文件**。
|
|
122
|
+
|
|
123
|
+
### 分账
|
|
124
|
+
|
|
125
|
+
| 位置 | 内容 |
|
|
126
|
+
|---|---|
|
|
127
|
+
| `$DSH_HOME/agents/codex/codex-providers.json`(0600) | **正本**:provider 清单 + 被显式删除的 endpoint 墓碑(含 API key) |
|
|
128
|
+
| `$DSH_HOME/agents/codex/codex-catalogs/<id>.json` | 本 adapter 自有的 per-provider 模型目录;经 `-c model_catalog_json=<绝对路径>` 注入 |
|
|
129
|
+
| `~/.codex/config.toml` | 用户原生:**只读**。启动时 + 每 10 分钟读一次,按 endpoint URL 去重折进正本 |
|
|
130
|
+
| `~/.codex/auth.json` | 用户原生:**只读**。`apiKey` 形态的 key 走子进程环境,不走这里 |
|
|
131
|
+
|
|
132
|
+
### 同步(2026-10-04 user 裁决)
|
|
133
|
+
|
|
134
|
+
`syncFromNative()`:启动时 + 每 10 分钟(`SYNC_INTERVAL_MS = 600_000`)读 `config.toml` 的**全部**
|
|
135
|
+
`[model_providers.<id>]` 表,按 endpoint URL 去重折进正本。新 endpoint 在库里没有名字,**就用 URL 端点
|
|
136
|
+
当名字**(`label = baseUrl`)——Codex 的 catalog 是「当前在役 provider」专用的,所以非在役 provider 的
|
|
137
|
+
模型清单**确实无从得知**,此时存 `models: []`(面板显示「no models yet」,该 provider 不注册路由),
|
|
138
|
+
而不是编一个。同步只**增/刷**、永不删;唯一的例外是用户显式删除留下的**墓碑**(endpoint key),
|
|
139
|
+
否则「删除」会在十分钟后自己撤销。
|
|
140
|
+
|
|
141
|
+
### 选择与切换
|
|
142
|
+
|
|
143
|
+
- **路由 = DSH 的**:每个有模型的 provider 注册一条 `ctx.llm` 路由,于是 `session/modelCatalog` 天然
|
|
144
|
+
按 provider 分组,`session/selectModel` 天然持久(`model/selection` + `modelSelection` 投影);
|
|
145
|
+
- **turn 边界判定 = DSH 的**:agent 每轮按 `pending ?? request/header ?? agentDefaultModel ?? options`
|
|
146
|
+
解析路由(`codex-route.ts`),并回写 `request/header`——于是投影的 `lastUsed`/`next`、
|
|
147
|
+
`consumeSelection`、以及「会话上次跑在哪个 provider」全部由上游自洽,UI 重放自然准确;
|
|
148
|
+
- **中途切换不用打断**:`turn/start` 的 `model` 覆盖「本轮及后续轮」,所以换**模型**是原生的;换
|
|
149
|
+
**provider** 必须换子进程——`turn/start` 没有 provider 字段,而打给**已加载**线程的 `thread/resume`
|
|
150
|
+
是「接受但忽略」(2026-10-03 实测:要 `zhipu-cn` 回 `deepseek`)。故 agent 在**下一轮冷启动**时
|
|
151
|
+
kill 掉旧 child、用新 `-c` 起新 child、`thread/resume` **同一个 thread id**,历史与上下文完整保留。
|
|
152
|
+
turn 中发起的切换落在下一轮(DSH 的 pending 语义),**不打断在跑的 turn**。
|
|
153
|
+
|
|
154
|
+
### 启动注入(零原生写入)
|
|
155
|
+
|
|
156
|
+
`codex-launch.ts` 生成 argv/env;三条实测约束写死在注释里:
|
|
157
|
+
|
|
158
|
+
1. hyphenated id 在 `-c` 点路径里合法(`model_providers.zhipu-cn.…`)⇒ 原生表名可原样作 provider id;
|
|
159
|
+
2. `model_catalog_json` 作为 override 时按**进程 cwd** 解析 ⇒ 路径必须绝对(相对路径实测 `ENOENT`);
|
|
160
|
+
3. `env_key` 是唯一不经过 auth manager 的形态 ⇒ 库里的 key 以合成变量名(`SUPERD_CODEX_KEY_<ID>`)
|
|
161
|
+
经**子进程环境**交给 codex,`auth.json` 完全不碰。**这也顺带解决了 ChatGPT 登录遮蔽 keyed provider
|
|
162
|
+
的老问题**(`requires_openai_auth` 才会被 `auth_mode=chatgpt` 遮蔽);只有「seeded」形态
|
|
163
|
+
(`apiKey` 且 value 为空 = key 在 auth.json 里)才回落到 `requires_openai_auth`,面板仍会告警。
|
|
164
|
+
|
|
165
|
+
### RPC
|
|
166
|
+
|
|
167
|
+
`TypertRemoteService`,namespace `codexProviders`(hub 经 `/hub/api?agent=codex` 原样转发):
|
|
168
|
+
`get` / `save` / `remove`。**API key 只写不读**——wire 上只有 `hasKey`,绝不回传值。
|
|
169
|
+
没有 `select`:选择是 DSH 的 per-session 状态。
|
|
170
|
+
|
|
171
|
+
### 模型目录必须克隆模板
|
|
172
|
+
|
|
173
|
+
codex 0.154 对 catalog 条目要求 `slug`/`display_name`/`supported_reasoning_levels`/`shell_type`/
|
|
174
|
+
`visibility`/`supported_in_api`/`priority`/`support_verbosity` 以及**嵌套 struct** `truncation_policy`…
|
|
175
|
+
字段链未终止,故只从既有条目克隆并覆盖身份字段。目录是**替换式**:一份目录只写它那个 provider 的模型
|
|
176
|
+
(2026-10-03 修正:早期「吸收且永不丢弃」让 Chat 模型清单只增不减)。
|
|
177
|
+
|
|
178
|
+
记录:`docs/superpowers/plans/2026-10-03-codex-multi-provider-hub.md` +
|
|
179
|
+
`docs/test-reports/2026-10-04-codex-multi-provider-onthefly.md`。
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# @pgmi-builds/agent-codex bundle patch (
|
|
1
|
+
# @pgmi-builds/agent-codex bundle patch (app-server line, standalone form).
|
|
2
2
|
# This file is the `dsh.bundle.patch` layer of the adapter package: when the
|
|
3
3
|
# codex world profile mounts the bundle, the boot merges THIS patch — mount
|
|
4
4
|
# the Codex provider plus disable the native components it replaces.
|
|
@@ -8,16 +8,17 @@
|
|
|
8
8
|
# fixture carries the 127.0.0.1:0 listener posture).
|
|
9
9
|
|
|
10
10
|
# Mount the Codex provider: a Cordis Service that registers an AgentFactory
|
|
11
|
-
# on ctx.agents. The provider drives
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
# config.toml +
|
|
11
|
+
# on ctx.agents. The provider drives one `codex app-server` child per session
|
|
12
|
+
# (stdio JSONL JSON-RPC; CodexAppServerClient, spawned lazily on the first
|
|
13
|
+
# prompt) plus thread resume by id; the model selector is served by a
|
|
14
|
+
# Codex-backed LlmAdapter reading the codex home's config.toml +
|
|
15
|
+
# model_catalog_json.
|
|
15
16
|
- insert:
|
|
16
17
|
- id: codex-provider
|
|
17
18
|
name: '@pgmi-builds/agent-codex'
|
|
18
19
|
|
|
19
20
|
# Codex owns the live agent transcript (the rollout JSONL); disable the
|
|
20
|
-
# built-in loop so it does not double-run alongside the
|
|
21
|
+
# built-in loop so it does not double-run alongside the app-server thread.
|
|
21
22
|
- id: agent-loop
|
|
22
23
|
disabled: true
|
|
23
24
|
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
- id: llm-pi-ai
|
|
30
31
|
disabled: true
|
|
31
32
|
|
|
32
|
-
# Codex is single-mode: the
|
|
33
|
+
# Codex is single-mode: the app-server thread drives tools itself, so no Dash preset
|
|
33
34
|
# composition is needed (the provider ships the fixed single-preset roster).
|
|
34
35
|
# 0.1.7: the host AgentPresetRegistry row (renamed `agent-presets` ->
|
|
35
36
|
# `agent-preset-registry`) stays MOUNTED — the adapter registers its one
|
|
@@ -43,9 +44,12 @@
|
|
|
43
44
|
# list/read/replay/workspace grouping are ordinary DSH services over that log.
|
|
44
45
|
# The adapter no longer provides its own persistence.
|
|
45
46
|
|
|
46
|
-
#
|
|
47
|
-
#
|
|
48
|
-
#
|
|
47
|
+
# The app-server line DOES have runtime approval control: the adapter folds
|
|
48
|
+
# `approval/policy` + `sandbox/mode` from the session log into the
|
|
49
|
+
# `turn/start` per-turn overrides (src/permission.ts turnPolicyFromEvents),
|
|
50
|
+
# so `/permission` is live. This table still supplies the LAUNCH posture and
|
|
51
|
+
# the fold's fallback. Default to danger-full-access. Restate the full
|
|
52
|
+
# 3-preset table: a patch
|
|
49
53
|
# with only defaultPreset silently drops the bundle's 3-preset table to the
|
|
50
54
|
# plugin's built-in 2, breaking the 3:3 Dash<->Codex pairing.
|
|
51
55
|
- id: permission
|