dsh-loop-engine 0.1.5-rc4 → 0.1.5-rc5
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/lib/index.js
CHANGED
|
@@ -685,6 +685,9 @@ function sessionModelOverrideOf(ctx, session) {
|
|
|
685
685
|
}
|
|
686
686
|
|
|
687
687
|
// src/driver-core/model-handover.ts
|
|
688
|
+
var SHIPPED_ROUTE_APIS = {
|
|
689
|
+
"deepseek-official": "openai-completions"
|
|
690
|
+
};
|
|
688
691
|
var warned = /* @__PURE__ */ new WeakMap();
|
|
689
692
|
function warnOnce(ctx, key, message) {
|
|
690
693
|
let seen = warned.get(ctx);
|
|
@@ -711,10 +714,9 @@ function readProviderProfile(ctx, address) {
|
|
|
711
714
|
const record = node;
|
|
712
715
|
const { baseURL, api, apiKeyEnv } = record;
|
|
713
716
|
if (typeof baseURL !== "string" || baseURL.length === 0) return void 0;
|
|
714
|
-
if (typeof api !== "string" || api.length === 0) return void 0;
|
|
715
717
|
return {
|
|
716
718
|
baseURL,
|
|
717
|
-
api,
|
|
719
|
+
api: typeof api === "string" && api.length > 0 ? api : void 0,
|
|
718
720
|
apiKeyEnv: typeof apiKeyEnv === "string" && apiKeyEnv.length > 0 ? apiKeyEnv : void 0
|
|
719
721
|
};
|
|
720
722
|
}
|
|
@@ -734,7 +736,7 @@ async function resolveModelHandover(ctx, override) {
|
|
|
734
736
|
}
|
|
735
737
|
const profile = readProviderProfile(ctx, address);
|
|
736
738
|
if (profile === void 0) {
|
|
737
|
-
return refuse(ctx, override, `the "${address.settingsNs}" settings section names no baseURL
|
|
739
|
+
return refuse(ctx, override, `the "${address.settingsNs}" settings section names no baseURL for it`);
|
|
738
740
|
}
|
|
739
741
|
const apiKey = await readApiKey(ctx, profile.apiKeyEnv);
|
|
740
742
|
if (apiKey === void 0) {
|
|
@@ -744,7 +746,7 @@ async function resolveModelHandover(ctx, override) {
|
|
|
744
746
|
provider: override.provider,
|
|
745
747
|
model: override.model,
|
|
746
748
|
baseURL: profile.baseURL,
|
|
747
|
-
api: profile.api,
|
|
749
|
+
api: profile.api ?? SHIPPED_ROUTE_APIS[override.provider],
|
|
748
750
|
apiKey
|
|
749
751
|
};
|
|
750
752
|
}
|
|
@@ -2333,15 +2335,15 @@ import { canonicalHeader as canonicalHeader2 } from "@deepseek-ai/dsh-session";
|
|
|
2333
2335
|
var CODEX_DSH_PROVIDER = "dsh";
|
|
2334
2336
|
var CODEX_DSH_API_KEY_ENV = "DSH_LOOP_ENGINE_API_KEY";
|
|
2335
2337
|
var CODEX_WIRE_APIS = {
|
|
2336
|
-
"openai-responses": "responses"
|
|
2337
|
-
"openai-completions": "chat"
|
|
2338
|
+
"openai-responses": "responses"
|
|
2338
2339
|
};
|
|
2339
2340
|
function tomlString(value) {
|
|
2340
2341
|
return `"${value.replaceAll("\\", "\\\\").replaceAll('"', '\\"')}"`;
|
|
2341
2342
|
}
|
|
2342
2343
|
function codexModelConfig(handover) {
|
|
2343
|
-
const wire = CODEX_WIRE_APIS[handover.api];
|
|
2344
|
+
const wire = handover.api === void 0 ? void 0 : CODEX_WIRE_APIS[handover.api];
|
|
2344
2345
|
const profile = [
|
|
2346
|
+
`name=${tomlString(CODEX_DSH_PROVIDER)}`,
|
|
2345
2347
|
`base_url=${tomlString(handover.baseURL)}`,
|
|
2346
2348
|
...wire === void 0 ? [] : [`wire_api=${tomlString(wire)}`],
|
|
2347
2349
|
`env_key=${tomlString(CODEX_DSH_API_KEY_ENV)}`
|
|
@@ -4325,10 +4327,11 @@ var PiAgent = class {
|
|
|
4325
4327
|
}
|
|
4326
4328
|
this.assertRequestHeader();
|
|
4327
4329
|
signal.throwIfAborted();
|
|
4328
|
-
const
|
|
4330
|
+
const resolved = await resolveModelHandover(
|
|
4329
4331
|
this.loopCtx,
|
|
4330
4332
|
sessionModelOverrideOf(this.loopCtx, this.session)
|
|
4331
4333
|
);
|
|
4334
|
+
const handover = resolved?.api === void 0 ? void 0 : resolved;
|
|
4332
4335
|
const controller = new AbortController();
|
|
4333
4336
|
const cancel = () => {
|
|
4334
4337
|
if (!controller.signal.aborted) {
|
|
@@ -4685,7 +4688,7 @@ var KIMI_PROVIDER_TYPES = {
|
|
|
4685
4688
|
"openai-responses": "openai"
|
|
4686
4689
|
};
|
|
4687
4690
|
function kimiModelEnv(handover) {
|
|
4688
|
-
const type = KIMI_PROVIDER_TYPES[handover.api];
|
|
4691
|
+
const type = handover.api === void 0 ? void 0 : KIMI_PROVIDER_TYPES[handover.api];
|
|
4689
4692
|
return {
|
|
4690
4693
|
KIMI_MODEL_NAME: handover.model,
|
|
4691
4694
|
KIMI_MODEL_API_KEY: handover.apiKey,
|
|
@@ -32,6 +32,11 @@
|
|
|
32
32
|
* and never a guess. The warning names the provider and the model, never a
|
|
33
33
|
* credential.
|
|
34
34
|
*
|
|
35
|
+
* What counts as "recognized" is deliberately narrow: a non-empty `baseURL` and
|
|
36
|
+
* a resolvable credential. The wire protocol is handed over when the deployment
|
|
37
|
+
* declares one, but its absence does NOT refuse the handover — see
|
|
38
|
+
* {@link resolveModelHandover} and {@link SHIPPED_ROUTE_APIS}.
|
|
39
|
+
*
|
|
35
40
|
* @module dsh-loop-engine/driver-core/model-handover
|
|
36
41
|
*/
|
|
37
42
|
import type { Context } from '@deepseek-ai/cordis';
|
|
@@ -54,8 +59,13 @@ export interface DshModelHandover {
|
|
|
54
59
|
readonly model: string;
|
|
55
60
|
/** Endpoint base as dsh configured it. */
|
|
56
61
|
readonly baseURL: string;
|
|
57
|
-
/**
|
|
58
|
-
|
|
62
|
+
/**
|
|
63
|
+
* dsh's wire protocol name for this endpoint, when the deployment declares
|
|
64
|
+
* one (or {@link SHIPPED_ROUTE_APIS} knows it for a shipped route). `undefined`
|
|
65
|
+
* is a normal answer, not a failure: engines that need a protocol degrade the
|
|
66
|
+
* way each one documents, and engines that do not (`claude-code`) ignore it.
|
|
67
|
+
*/
|
|
68
|
+
readonly api: string | undefined;
|
|
59
69
|
/** The resolved credential value; never logged, never evented. */
|
|
60
70
|
readonly apiKey: string;
|
|
61
71
|
}
|
|
@@ -102,8 +112,16 @@ export interface CredentialsService {
|
|
|
102
112
|
* `undefined` is the answer in exactly two situations: the selection names no
|
|
103
113
|
* real dsh model ({@link SessionModelOverride} is already `undefined` for the
|
|
104
114
|
* hosted seat), or a real model whose endpoint/credential dsh does not disclose
|
|
105
|
-
* to this read
|
|
106
|
-
* operator can see and fix, not a silent downgrade.
|
|
115
|
+
* to this read — no `baseURL`, or no credential. Both warn once: they are
|
|
116
|
+
* deployment-shape gaps the operator can see and fix, not a silent downgrade.
|
|
117
|
+
*
|
|
118
|
+
* The wire protocol is NOT such a gate. A profile that names no `api` still
|
|
119
|
+
* hands over its endpoint (with `api: undefined`), because refusing would let
|
|
120
|
+
* the engine send dsh's model id to the engine's OWN endpoint — a failure that
|
|
121
|
+
* reads like an auth or model problem while the real one is "wrong endpoint".
|
|
122
|
+
* Shipped routes whose adapter owns the wire are named in
|
|
123
|
+
* {@link SHIPPED_ROUTE_APIS} so they hand over a real protocol; anything still
|
|
124
|
+
* unknown degrades per engine, which is the engine's call to make.
|
|
107
125
|
*
|
|
108
126
|
* Called fresh on every step by each driver, so a model or provider picked
|
|
109
127
|
* mid-conversation reaches the engine's next request rather than being frozen
|
|
@@ -3,17 +3,28 @@
|
|
|
3
3
|
* overrides and environment that point it at dsh's model.
|
|
4
4
|
*
|
|
5
5
|
* Codex resolves a custom endpoint through `model_providers.<id>` in its own
|
|
6
|
-
* `config.toml` (`base_url`, `wire_api`, and an `env_key` naming the
|
|
7
|
-
* the credential is read from), and `codex app-server` accepts those as
|
|
8
|
-
* key=value` overrides — so the handover needs no edit of `~/.codex`. The
|
|
6
|
+
* `config.toml` (`name`, `base_url`, `wire_api`, and an `env_key` naming the
|
|
7
|
+
* variable the credential is read from), and `codex app-server` accepts those as
|
|
8
|
+
* `-c key=value` overrides — so the handover needs no edit of `~/.codex`. The
|
|
9
9
|
* credential travels in the child's environment under {@link CODEX_DSH_API_KEY_ENV},
|
|
10
10
|
* which the `env_key` names.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
12
|
+
* `name` is not optional in practice even though the CLI's own docs describe it
|
|
13
|
+
* as display metadata: codex 0.149.1 (the version this plugin pins) refuses to
|
|
14
|
+
* load a provider whose `name` is empty — "provider name must not be empty in
|
|
15
|
+
* `model_providers`" — and that config error kills `app-server` on startup, which
|
|
16
|
+
* the driver can only report as "process exited unexpectedly". Omitting it looked
|
|
17
|
+
* correct and failed before any request was ever sent, so every override this
|
|
18
|
+
* module builds carries it (verified against the pinned binary).
|
|
19
|
+
*
|
|
20
|
+
* Codex speaks only OpenAI's `responses` wire as of the version this plugin pins
|
|
21
|
+
* (0.149.1 dropped `chat`). A dsh protocol with no codex equivalent (Anthropic
|
|
22
|
+
* Messages, and now OpenAI Chat Completions) is NOT guessed: `wire_api` is
|
|
23
|
+
* omitted, so codex falls back to its own default wire and fails loud on the
|
|
24
|
+
* request — the honest outcome, since the plugin cannot make codex speak a
|
|
25
|
+
* protocol it does not implement. That default is `responses` as of 0.149.1: the
|
|
26
|
+
* request lands on `<baseURL>/responses`, which an Anthropic Messages or Chat
|
|
27
|
+
* Completions endpoint does not serve.
|
|
17
28
|
*
|
|
18
29
|
* @module dsh-loop-engine/engine-codex/model-handover
|
|
19
30
|
*/
|
|
@@ -36,7 +47,8 @@ export interface CodexModelConfig {
|
|
|
36
47
|
* The provider id ({@link CODEX_DSH_PROVIDER}) is a plugin-owned name: it exists
|
|
37
48
|
* only in this child's command line, so it cannot collide with a provider the
|
|
38
49
|
* user configured, and the model itself is still handed over as the thread's own
|
|
39
|
-
* `model` param.
|
|
50
|
+
* `model` param. The provider's `name` repeats that id because codex rejects an
|
|
51
|
+
* empty one at config load, before any request is made.
|
|
40
52
|
* @param handover - the resolved dsh endpoint for the session's selection.
|
|
41
53
|
* @returns the argv entries and environment to spawn the app-server with.
|
|
42
54
|
*/
|
|
@@ -17,6 +17,10 @@
|
|
|
17
17
|
* user's own `~/.pi` skills/auth/theme. That is the trade the deployment makes
|
|
18
18
|
* by selecting a real dsh model on pi.
|
|
19
19
|
*
|
|
20
|
+
* pi's provider schema requires a wire protocol (`api`), so this is the one
|
|
21
|
+
* engine that cannot express a handover without one; the driver drops such a
|
|
22
|
+
* handover before it reaches here instead of writing a file pi rejects.
|
|
23
|
+
*
|
|
20
24
|
* @module dsh-loop-engine/engine-pi/model-handover
|
|
21
25
|
*/
|
|
22
26
|
import type { DshModelHandover } from '../driver-core/model-handover.ts';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-loop-engine",
|
|
3
3
|
"description": "Web-switchable agent loop engine selection for the DeepSeek Harness - out-of-tree plugin (Claude Code / Codex / Pi / Kimi Code drivers) maintained by @kuun993, zero main-repo changes",
|
|
4
|
-
"version": "0.1.5-
|
|
4
|
+
"version": "0.1.5-rc5",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
7
7
|
},
|