@qoder-ai/qoder-agent-sdk 1.0.54 → 1.0.55
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/dist/daemon/daemon-connection.d.ts +121 -1
- package/dist/daemon/daemon-session-transport.d.ts +3 -1
- package/dist/daemon/global-daemon.d.ts +6 -3
- package/dist/daemon/protocol.d.ts +73 -5
- package/dist/daemon/start-daemon.d.ts +116 -14
- package/dist/index.d.ts +5 -3
- package/dist/index.js +33 -33
- package/dist/query/query-runner.d.ts +6 -1
- package/dist/runtime-manifest.json +5 -5
- package/dist/types/plugins.d.ts +17 -0
- package/package.json +2 -2
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
import type { Readable, Writable } from "node:stream";
|
|
2
2
|
import { type DaemonCommandResultMap, type DaemonCommandParamsMap, type DaemonControlRequestFrame, type DaemonQueryMethod, type DaemonWireSessionMessage, type JsonObject, type JsonValue, type OpenSessionParams, type RenameSessionResult } from "./protocol.js";
|
|
3
3
|
import type { SdkAuthPayload } from "../types/auth.js";
|
|
4
|
+
import type { PluginValidationReport } from "../types/plugins.js";
|
|
4
5
|
import { DaemonSessionTransport, type DaemonSessionTransportOptions } from "./daemon-session-transport.js";
|
|
5
6
|
import type { DiagnosticsSink } from "../core/sdk-diagnostics.js";
|
|
6
7
|
export declare const SESSION_STORE_FILE_CHECKPOINTING_CAPABILITY = "session_store_file_checkpointing_v1";
|
|
7
8
|
export declare const SESSION_STORE_FORK_BARRIER_CAPABILITY = "session_store_fork_barrier_v1";
|
|
9
|
+
/**
|
|
10
|
+
* 心跳判死阈值:30s 无任何入站帧即判 daemon 失活。与 CLI 仓
|
|
11
|
+
* DAEMON_KEEP_ALIVE_INTERVAL_MS(5s 发送周期,本值 = 6 周期)镜像;能力常量
|
|
12
|
+
* DAEMON_KEEP_ALIVE_CAPABILITY 同为两仓镜像,靠握手协商门控——组合不匹配时
|
|
13
|
+
* 最多不武装看门狗,不会误判。
|
|
14
|
+
*/
|
|
15
|
+
export declare const DAEMON_HEARTBEAT_TIMEOUT_MS = 30000;
|
|
16
|
+
export declare const DAEMON_KEEP_ALIVE_CAPABILITY = "daemon_keep_alive_v1";
|
|
17
|
+
/**
|
|
18
|
+
* daemon 会话 close 改成「关信道即回包、后台排干 teardown」的能力位(CLI 仓镜像)。
|
|
19
|
+
* 会话 initialize 回包声明它时,QueryRunner.close 不再隐式等 memory / evolution
|
|
20
|
+
* flush;旧 CLI 不声明则保持原有等待语义(版本错配保护)。
|
|
21
|
+
*/
|
|
22
|
+
export declare const DAEMON_ASYNC_SESSION_TEARDOWN_CAPABILITY = "daemon_async_session_teardown_v1";
|
|
8
23
|
export interface DaemonConnectionOptions {
|
|
9
24
|
input: Writable;
|
|
10
25
|
output: Readable;
|
|
@@ -27,6 +42,11 @@ export interface DaemonConnectionOptions {
|
|
|
27
42
|
* 只打协议元数据(方法名、id、耗时、字节数),绝不打帧原文、凭据与 prompt 正文。
|
|
28
43
|
*/
|
|
29
44
|
diagnostics?: DiagnosticsSink;
|
|
45
|
+
/**
|
|
46
|
+
* 心跳看门狗阈值(ms),缺省 DAEMON_HEARTBEAT_TIMEOUT_MS;0 = 关闭(逃生口)。
|
|
47
|
+
* 仅握手协商出 daemon_keep_alive_v1 时武装;单调钟判定,机器睡眠/唤醒不误杀。
|
|
48
|
+
*/
|
|
49
|
+
heartbeatTimeoutMs?: number;
|
|
30
50
|
}
|
|
31
51
|
export interface DaemonInitializeOptions {
|
|
32
52
|
/** Advertised in addition to the capability this SDK cannot work without. */
|
|
@@ -38,6 +58,11 @@ export interface DaemonInitializeOptions {
|
|
|
38
58
|
* without it. Carries a plaintext credential — never log it.
|
|
39
59
|
*/
|
|
40
60
|
auth?: SdkAuthPayload;
|
|
61
|
+
/**
|
|
62
|
+
* Process-wide proxy applied during the handshake (`daemon_proxy_v1`).
|
|
63
|
+
* An empty string clears a previously configured proxy.
|
|
64
|
+
*/
|
|
65
|
+
proxy?: string;
|
|
41
66
|
}
|
|
42
67
|
export type DaemonRequestHandler = (request: DaemonControlRequestFrame) => Promise<JsonValue>;
|
|
43
68
|
export declare class DaemonRpcError extends Error {
|
|
@@ -62,13 +87,50 @@ export declare class DaemonRequestError extends Error {
|
|
|
62
87
|
details?: JsonObject;
|
|
63
88
|
});
|
|
64
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* A second concurrent Query declared a session id that is already opening or
|
|
92
|
+
* open on this daemon connection. Thrown synchronously from `query()` so the
|
|
93
|
+
* caller sees the conflict before any frame is sent.
|
|
94
|
+
*/
|
|
95
|
+
export declare class DaemonSessionAlreadyOpenError extends Error {
|
|
96
|
+
readonly sessionId: string;
|
|
97
|
+
readonly state: "opening" | "open";
|
|
98
|
+
readonly code = "SESSION_ALREADY_OPEN";
|
|
99
|
+
constructor(sessionId: string, state: "opening" | "open");
|
|
100
|
+
}
|
|
101
|
+
/** `close` 进行中的 id 不会拒绝新 Query;凭据里的 ready 在 close 出清后兑现。 */
|
|
102
|
+
export interface DaemonSessionIdClaim {
|
|
103
|
+
readonly sessionId: string;
|
|
104
|
+
readonly ready: Promise<void>;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* 心跳看门狗判死:daemon「活着但静默」(事件循环卡死、管道半开、OOM 挂持)时
|
|
108
|
+
* 唯一的判定手段。message 以错误码开头——app 侧按约定取 message 前 120 字符做
|
|
109
|
+
* failureCode,码在开头才可检索。
|
|
110
|
+
*/
|
|
111
|
+
export declare class DaemonHeartbeatTimeoutError extends Error {
|
|
112
|
+
readonly code = "DAEMON_HEARTBEAT_TIMEOUT";
|
|
113
|
+
readonly elapsedMs: number;
|
|
114
|
+
constructor(elapsedMs: number);
|
|
115
|
+
}
|
|
65
116
|
export declare class DaemonConnection {
|
|
66
117
|
private readonly input;
|
|
67
|
-
|
|
118
|
+
/**
|
|
119
|
+
* Daemon-level reverse-request handler (the `daemon.auth.*` host-callback bridge).
|
|
120
|
+
* Mutable: `Daemon.auth(payload)` can rebind it when a later payload switches the
|
|
121
|
+
* host-callback arm (jobToken / serviceAccount-token-provider), so the daemon's
|
|
122
|
+
* token fetch for the *new* credentials reaches the right host callback.
|
|
123
|
+
*/
|
|
124
|
+
private requestHandler;
|
|
68
125
|
private readonly pendingRequests;
|
|
69
126
|
private readonly timedOutRequestIds;
|
|
70
127
|
private readonly activeInboundRequestIds;
|
|
71
128
|
private readonly sessions;
|
|
129
|
+
/**
|
|
130
|
+
* 声明 id 的占用表:query() 创建 transport 时同步占位,回包前就能拦住第二个
|
|
131
|
+
* 同 id Query。close 期间到达的 Query 排队等 close 出清,不误杀顺序重开。
|
|
132
|
+
*/
|
|
133
|
+
private readonly sessionSlots;
|
|
72
134
|
private readonly closedSessionIds;
|
|
73
135
|
/**
|
|
74
136
|
* 每个 daemon-bound 会话 open 时携带的工作目录(sessionId → cwd)。daemon 已无 cwd
|
|
@@ -93,10 +155,46 @@ export declare class DaemonConnection {
|
|
|
93
155
|
private readonly failureListeners;
|
|
94
156
|
private readonly describeUnexpectedClose;
|
|
95
157
|
private readonly diagnostics;
|
|
158
|
+
/**
|
|
159
|
+
* 心跳看门狗:最近一次入站帧的单调钟时刻(任意入站帧都刷新——有正常会话流量
|
|
160
|
+
* 时天然免检,keep_alive 只是空闲期保底节拍)。单调钟使机器睡眠/唤醒后差值仍小,
|
|
161
|
+
* 不误杀。看门狗定时器与阈值见 armHeartbeatWatchdog。
|
|
162
|
+
*/
|
|
163
|
+
private lastInboundAt;
|
|
164
|
+
private heartbeatWatchdog;
|
|
165
|
+
private readonly heartbeatTimeoutMs;
|
|
96
166
|
constructor(options: DaemonConnectionOptions);
|
|
97
167
|
initialize(sdkVersion: string, options?: DaemonInitializeOptions): Promise<void>;
|
|
98
168
|
createSessionTransport(options: DaemonSessionTransportOptions): DaemonSessionTransport;
|
|
99
169
|
supportsCapability(capability: string): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Switches the daemon-level (process-wide) proxy, or clears it with
|
|
172
|
+
* `undefined` / `null` / an empty string. Returns the normalized value.
|
|
173
|
+
*/
|
|
174
|
+
setProxy(proxy?: string | null): Promise<string | null>;
|
|
175
|
+
/**
|
|
176
|
+
* 同步占用一个声明 id。opening/open 直接抛冲突;closing 则排队,ready 在
|
|
177
|
+
* 前一次 close 出清后兑现。未声明 id(daemon 现 mint)不会撞,调用方不占用。
|
|
178
|
+
*/
|
|
179
|
+
claimSessionId(sessionId: string): DaemonSessionIdClaim;
|
|
180
|
+
markSessionOpen(sessionId: string): void;
|
|
181
|
+
markSessionClosing(sessionId: string): void;
|
|
182
|
+
/** open 失败/放弃时出清占位;不向等待者交接(close 才有资格交接)。 */
|
|
183
|
+
releaseSessionClaim(sessionId: string): void;
|
|
184
|
+
private completeSessionClose;
|
|
185
|
+
private advanceSessionSlot;
|
|
186
|
+
/**
|
|
187
|
+
* Statically validates local plugins inside the daemon. Gated on
|
|
188
|
+
* `daemon_validate_plugins_v1` so an older CLI rejects here instead of
|
|
189
|
+
* answering `METHOD_NOT_FOUND`; the caller falls back to the Worker path.
|
|
190
|
+
*/
|
|
191
|
+
validatePlugins(paths: readonly string[], configDir?: string): Promise<PluginValidationReport[]>;
|
|
192
|
+
/**
|
|
193
|
+
* Rebinds the daemon-level reverse-request handler. Used by `Daemon.auth(payload)`
|
|
194
|
+
* when the new credentials carry a host-callback arm, so the daemon's token fetch
|
|
195
|
+
* for the overridden credentials is answered by the matching host callback.
|
|
196
|
+
*/
|
|
197
|
+
setRequestHandler(handler: DaemonRequestHandler | undefined): void;
|
|
100
198
|
onFailure(listener: (error: Error) => void): () => void;
|
|
101
199
|
openSession(params: OpenSessionParams, transport: DaemonSessionTransport): Promise<string>;
|
|
102
200
|
listSessions(cwd?: string): Promise<import("./protocol.js").DaemonSessionInfo[]>;
|
|
@@ -113,6 +211,20 @@ export declare class DaemonConnection {
|
|
|
113
211
|
* fails that one query, not the connection.
|
|
114
212
|
*/
|
|
115
213
|
query<Method extends DaemonQueryMethod>(method: Method, params: DaemonCommandParamsMap[Method]): Promise<DaemonCommandResultMap[Method]>;
|
|
214
|
+
/**
|
|
215
|
+
* Explicitly triggers the daemon's on-demand credential landing
|
|
216
|
+
* (`daemon.authenticate`). The handshake only validated the payload (and auth is
|
|
217
|
+
* optional there), so this is the host-facing way to land credentials up front.
|
|
218
|
+
*
|
|
219
|
+
* `payload` omitted → authenticate with the credentials the daemon already holds.
|
|
220
|
+
* `payload` present → override the held credentials, then authenticate. Idempotent
|
|
221
|
+
* on the CLI side for the no-payload form.
|
|
222
|
+
*
|
|
223
|
+
* Gated on `daemon_queries_v1` (always advertised by a CLI that speaks this
|
|
224
|
+
* protocol); an old CLI that lacks the method rejects here with a clear protocol
|
|
225
|
+
* error instead of a bare METHOD_NOT_FOUND frame.
|
|
226
|
+
*/
|
|
227
|
+
authenticate(payload?: SdkAuthPayload): Promise<DaemonCommandResultMap["authenticate"]>;
|
|
116
228
|
shutdown(timeoutMs?: number): Promise<void>;
|
|
117
229
|
/**
|
|
118
230
|
* EOF 落定前问一次进程侧:对端是不是已经退了、为什么退。
|
|
@@ -120,6 +232,14 @@ export declare class DaemonConnection {
|
|
|
120
232
|
*/
|
|
121
233
|
private resolveUnexpectedClose;
|
|
122
234
|
fail(error: unknown, notifyListeners?: boolean): void;
|
|
235
|
+
/**
|
|
236
|
+
* 心跳看门狗:每 5s 检查一次距最近入站帧的单调钟差值,超阈值即判 daemon 失活。
|
|
237
|
+
* 判定后走既有 fail() 全量传播(在途请求 reject、在途会话流 error 终止、后续调用
|
|
238
|
+
* 立即 reject、failureListeners 通知)——「对外抛错」不需要新机制。
|
|
239
|
+
* 定时器 unref:看门狗是宿主的判定器,不该替宿主保活进程。
|
|
240
|
+
*/
|
|
241
|
+
private armHeartbeatWatchdog;
|
|
242
|
+
private disarmHeartbeatWatchdog;
|
|
123
243
|
private request;
|
|
124
244
|
private readOutput;
|
|
125
245
|
private acceptFrame;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type { Transport } from '../core/transport.js';
|
|
2
2
|
import type { StdoutMessage } from '../types/control.js';
|
|
3
3
|
import type { DaemonWireSessionMessage } from './protocol.js';
|
|
4
|
-
import type { DaemonConnection } from './daemon-connection.js';
|
|
4
|
+
import type { DaemonConnection, DaemonSessionIdClaim } from './daemon-connection.js';
|
|
5
5
|
import type { DiagnosticsSink } from '../core/sdk-diagnostics.js';
|
|
6
6
|
export type DaemonSessionTransportOptions = {
|
|
7
7
|
workerArgs: string[];
|
|
8
8
|
cwd?: string;
|
|
9
9
|
configDir?: string;
|
|
10
|
+
/** query() 创建时按声明 id 占到的位置;close 进行中时先等 ready。 */
|
|
11
|
+
claim?: DaemonSessionIdClaim;
|
|
10
12
|
cleanup?: () => void;
|
|
11
13
|
/**
|
|
12
14
|
* 由 DaemonConnection.createSessionTransport 注入,调用方不需要传。
|
|
@@ -2,11 +2,14 @@ import type { InternalAuthOptions } from '../types/auth.js';
|
|
|
2
2
|
import { type Daemon } from './start-daemon.js';
|
|
3
3
|
export interface InitDaemonOptions {
|
|
4
4
|
auth: InternalAuthOptions;
|
|
5
|
-
/** Idle Worker timeout in milliseconds. Set to 0 to disable reclamation. */
|
|
6
|
-
workerIdleTimeoutMs?: number;
|
|
7
|
-
cwd?: string;
|
|
8
5
|
pathToQoderCLIExecutable?: string;
|
|
6
|
+
/** 语义同 `StartDaemonOptions.executable`。 */
|
|
7
|
+
executable?: string;
|
|
8
|
+
/** 语义同 `StartDaemonOptions.executableArgs`。 */
|
|
9
|
+
executableArgs?: string[];
|
|
9
10
|
proxy?: string;
|
|
11
|
+
/** 语义同 `StartDaemonOptions.vpcEndpoint`。 */
|
|
12
|
+
vpcEndpoint?: string;
|
|
10
13
|
env?: Record<string, string | undefined>;
|
|
11
14
|
/** 语义同 `StartDaemonOptions.stderr`:daemon 子进程 stderr 的实时回调。 */
|
|
12
15
|
stderr?: (data: string) => void;
|
|
@@ -5,15 +5,29 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { BYOKModelValidationInput, BYOKProviderInfo, ByokConfigCheckResult, ByokConfigInfo, ByokConfigReference, CheckByokConfigInput, CreateByokConfigInput, DeleteByokConfigInput, UpdateByokConfigInput } from "../protocol/control.js";
|
|
7
7
|
import type { AccountInfo, ModelInfo, SessionCreditsUsage, UsageInfo } from "../protocol/common.js";
|
|
8
|
-
import type { PluginDetails } from "../types/plugins.js";
|
|
8
|
+
import type { PluginDetails, PluginValidationReport } from "../types/plugins.js";
|
|
9
9
|
import type { SdkAuthPayload } from "../types/auth.js";
|
|
10
10
|
export declare const DAEMON_PROTOCOL_VERSION: 2;
|
|
11
11
|
/**
|
|
12
12
|
* Reported by the daemon in its initialize result once it accepted an `auth`
|
|
13
|
-
* payload, i.e. when the account-level query plane
|
|
14
|
-
*
|
|
13
|
+
* payload, i.e. when the account-level query plane (and the explicit
|
|
14
|
+
* `daemon.authenticate` trigger) is available on this connection. Acceptance is
|
|
15
|
+
* shape validation only — the credentials land on demand, so queries before the
|
|
16
|
+
* first landing may answer `AUTH_REQUIRED`. Absent for a daemon that only
|
|
17
|
+
* manages Sessions.
|
|
15
18
|
*/
|
|
16
19
|
export declare const DAEMON_QUERIES_CAPABILITY = "daemon_queries_v1";
|
|
20
|
+
/**
|
|
21
|
+
* The daemon can statically validate local plugins in-process
|
|
22
|
+
* (`daemon.validate_plugins`), so the SDK can skip spawning a Worker for
|
|
23
|
+
* plugin validation. Absent on older CLIs; callers must fall back.
|
|
24
|
+
*/
|
|
25
|
+
export declare const DAEMON_VALIDATE_PLUGINS_CAPABILITY = "daemon_validate_plugins_v1";
|
|
26
|
+
/**
|
|
27
|
+
* The daemon can apply a process-wide proxy during the handshake (`initialize`)
|
|
28
|
+
* and switch it later via `daemon.setproxy`.
|
|
29
|
+
*/
|
|
30
|
+
export declare const DAEMON_PROXY_CAPABILITY = "daemon_proxy_v1";
|
|
17
31
|
export type JsonPrimitive = string | number | boolean | null;
|
|
18
32
|
export type JsonValue = JsonPrimitive | JsonValue[] | {
|
|
19
33
|
[key: string]: JsonValue;
|
|
@@ -83,6 +97,11 @@ export type InitializeDaemonParams = {
|
|
|
83
97
|
* message.
|
|
84
98
|
*/
|
|
85
99
|
auth?: SdkAuthPayload;
|
|
100
|
+
/**
|
|
101
|
+
* Process-wide proxy applied during the handshake (`daemon_proxy_v1`). An
|
|
102
|
+
* empty string clears a previously configured proxy.
|
|
103
|
+
*/
|
|
104
|
+
proxy?: string;
|
|
86
105
|
};
|
|
87
106
|
export type InitializeDaemonResult = {
|
|
88
107
|
daemon_protocol_version: typeof DAEMON_PROTOCOL_VERSION;
|
|
@@ -138,6 +157,31 @@ export type DeleteSessionParams = {
|
|
|
138
157
|
cwd?: string;
|
|
139
158
|
};
|
|
140
159
|
export type ShutdownParams = Record<string, never>;
|
|
160
|
+
/**
|
|
161
|
+
* Explicit auth trigger (`daemon.authenticate`, surfaced as `Daemon.auth(payload?)`).
|
|
162
|
+
* The initialize handshake only validates the credential payload (and auth is now
|
|
163
|
+
* optional there); the CLI lands it on demand — the first auth-needing consumer
|
|
164
|
+
* (this method, an account-level query, or a session's inference readiness) starts
|
|
165
|
+
* the login.
|
|
166
|
+
*
|
|
167
|
+
* `auth` is optional:
|
|
168
|
+
* - omitted → authenticate with the credentials the daemon already holds (from
|
|
169
|
+
* `startDaemon`); rejected with `AUTH_PAYLOAD_REQUIRED` if it holds none.
|
|
170
|
+
* - present → **override** the held credentials with this payload, then authenticate
|
|
171
|
+
* (supports supplying credentials to a daemon started without auth, and switching
|
|
172
|
+
* accounts on an already-authenticated daemon).
|
|
173
|
+
*/
|
|
174
|
+
export type DaemonAuthenticateParams = {
|
|
175
|
+
auth?: SdkAuthPayload;
|
|
176
|
+
};
|
|
177
|
+
export type DaemonAuthenticateResult = {
|
|
178
|
+
/**
|
|
179
|
+
* False is a non-fatal "no credential" outcome (e.g. the read-only borrow of
|
|
180
|
+
* the local qodercli login found nothing). Rejected credentials arrive as an
|
|
181
|
+
* error frame instead, never as `authenticated: false`.
|
|
182
|
+
*/
|
|
183
|
+
authenticated: boolean;
|
|
184
|
+
};
|
|
141
185
|
/**
|
|
142
186
|
* Account-level query plane (`daemon_queries_v1`).
|
|
143
187
|
*
|
|
@@ -202,6 +246,24 @@ export type DaemonListPluginsParams = Record<string, never>;
|
|
|
202
246
|
export type DaemonListPluginsResult = {
|
|
203
247
|
plugins: PluginDetails[];
|
|
204
248
|
};
|
|
249
|
+
/**
|
|
250
|
+
* Static, session-less plugin validation. `config_dir` is the base directory
|
|
251
|
+
* for relative paths, mirroring the Worker path's `QODER_CONFIG_DIR` context.
|
|
252
|
+
*/
|
|
253
|
+
export type DaemonValidatePluginsParams = {
|
|
254
|
+
paths: string[];
|
|
255
|
+
config_dir?: string;
|
|
256
|
+
};
|
|
257
|
+
export type DaemonValidatePluginsResult = {
|
|
258
|
+
reports: PluginValidationReport[];
|
|
259
|
+
};
|
|
260
|
+
export type DaemonSetProxyParams = {
|
|
261
|
+
/** `null` clears the daemon-level proxy. */
|
|
262
|
+
proxy: string | null;
|
|
263
|
+
};
|
|
264
|
+
export type DaemonSetProxyResult = {
|
|
265
|
+
proxy: string | null;
|
|
266
|
+
};
|
|
205
267
|
export type DaemonGetUsageInfoParams = Record<string, never>;
|
|
206
268
|
export type DaemonGetUsageInfoResult = {
|
|
207
269
|
usage: UsageInfo | null;
|
|
@@ -213,7 +275,7 @@ export type DaemonAccountInfoParams = Record<string, never>;
|
|
|
213
275
|
export type DaemonAccountInfoResult = {
|
|
214
276
|
account: AccountInfo;
|
|
215
277
|
};
|
|
216
|
-
export type DaemonCommandMethod = "initialize" | "open_session" | "list_sessions" | "rename_session" | "close_session" | "delete_session" | "shutdown" | DaemonQueryMethod;
|
|
278
|
+
export type DaemonCommandMethod = "initialize" | "open_session" | "list_sessions" | "rename_session" | "close_session" | "delete_session" | "shutdown" | "authenticate" | "validate_plugins" | "setproxy" | DaemonQueryMethod;
|
|
217
279
|
export interface DaemonCommandParamsMap {
|
|
218
280
|
initialize: InitializeDaemonParams;
|
|
219
281
|
open_session: OpenSessionParams;
|
|
@@ -222,6 +284,7 @@ export interface DaemonCommandParamsMap {
|
|
|
222
284
|
close_session: CloseSessionParams;
|
|
223
285
|
delete_session: DeleteSessionParams;
|
|
224
286
|
shutdown: ShutdownParams;
|
|
287
|
+
authenticate: DaemonAuthenticateParams;
|
|
225
288
|
get_models: DaemonGetModelsParams;
|
|
226
289
|
get_byok_config: DaemonGetByokConfigParams;
|
|
227
290
|
validate_byok_model: DaemonValidateByokModelParams;
|
|
@@ -231,10 +294,12 @@ export interface DaemonCommandParamsMap {
|
|
|
231
294
|
delete_byok_config: DaemonDeleteByokConfigParams;
|
|
232
295
|
check_byok_config: DaemonCheckByokConfigParams;
|
|
233
296
|
list_plugins: DaemonListPluginsParams;
|
|
297
|
+
validate_plugins: DaemonValidatePluginsParams;
|
|
298
|
+
setproxy: DaemonSetProxyParams;
|
|
234
299
|
get_usage_info: DaemonGetUsageInfoParams;
|
|
235
300
|
account_info: DaemonAccountInfoParams;
|
|
236
301
|
}
|
|
237
|
-
export type DaemonCommandRequest = DaemonControlRequestFrame<"initialize", InitializeDaemonParams> | DaemonControlRequestFrame<"open_session", OpenSessionParams> | DaemonControlRequestFrame<"list_sessions", ListSessionsParams> | DaemonControlRequestFrame<"rename_session", RenameSessionParams> | DaemonControlRequestFrame<"close_session", CloseSessionParams> | DaemonControlRequestFrame<"delete_session", DeleteSessionParams> | DaemonControlRequestFrame<"shutdown", ShutdownParams> | DaemonControlRequestFrame<"get_models", DaemonGetModelsParams> | DaemonControlRequestFrame<"get_byok_config", DaemonGetByokConfigParams> | DaemonControlRequestFrame<"validate_byok_model", DaemonValidateByokModelParams> | DaemonControlRequestFrame<"list_byok_configs", DaemonListByokConfigsParams> | DaemonControlRequestFrame<"create_byok_config", DaemonCreateByokConfigParams> | DaemonControlRequestFrame<"update_byok_config", DaemonUpdateByokConfigParams> | DaemonControlRequestFrame<"delete_byok_config", DaemonDeleteByokConfigParams> | DaemonControlRequestFrame<"check_byok_config", DaemonCheckByokConfigParams> | DaemonControlRequestFrame<"list_plugins", DaemonListPluginsParams> | DaemonControlRequestFrame<"get_usage_info", DaemonGetUsageInfoParams> | DaemonControlRequestFrame<"account_info", DaemonAccountInfoParams>;
|
|
302
|
+
export type DaemonCommandRequest = DaemonControlRequestFrame<"initialize", InitializeDaemonParams> | DaemonControlRequestFrame<"open_session", OpenSessionParams> | DaemonControlRequestFrame<"list_sessions", ListSessionsParams> | DaemonControlRequestFrame<"rename_session", RenameSessionParams> | DaemonControlRequestFrame<"close_session", CloseSessionParams> | DaemonControlRequestFrame<"delete_session", DeleteSessionParams> | DaemonControlRequestFrame<"shutdown", ShutdownParams> | DaemonControlRequestFrame<"authenticate", DaemonAuthenticateParams> | DaemonControlRequestFrame<"get_models", DaemonGetModelsParams> | DaemonControlRequestFrame<"get_byok_config", DaemonGetByokConfigParams> | DaemonControlRequestFrame<"validate_byok_model", DaemonValidateByokModelParams> | DaemonControlRequestFrame<"list_byok_configs", DaemonListByokConfigsParams> | DaemonControlRequestFrame<"create_byok_config", DaemonCreateByokConfigParams> | DaemonControlRequestFrame<"update_byok_config", DaemonUpdateByokConfigParams> | DaemonControlRequestFrame<"delete_byok_config", DaemonDeleteByokConfigParams> | DaemonControlRequestFrame<"check_byok_config", DaemonCheckByokConfigParams> | DaemonControlRequestFrame<"list_plugins", DaemonListPluginsParams> | DaemonControlRequestFrame<"validate_plugins", DaemonValidatePluginsParams> | DaemonControlRequestFrame<"setproxy", DaemonSetProxyParams> | DaemonControlRequestFrame<"get_usage_info", DaemonGetUsageInfoParams> | DaemonControlRequestFrame<"account_info", DaemonAccountInfoParams>;
|
|
238
303
|
export interface DaemonCommandResultMap {
|
|
239
304
|
initialize: InitializeDaemonResult;
|
|
240
305
|
open_session: OpenSessionResult;
|
|
@@ -243,6 +308,7 @@ export interface DaemonCommandResultMap {
|
|
|
243
308
|
close_session: null;
|
|
244
309
|
delete_session: null;
|
|
245
310
|
shutdown: null;
|
|
311
|
+
authenticate: DaemonAuthenticateResult;
|
|
246
312
|
get_models: DaemonGetModelsResult;
|
|
247
313
|
get_byok_config: DaemonGetByokConfigResult;
|
|
248
314
|
validate_byok_model: DaemonValidateByokModelResult;
|
|
@@ -252,6 +318,8 @@ export interface DaemonCommandResultMap {
|
|
|
252
318
|
delete_byok_config: null;
|
|
253
319
|
check_byok_config: DaemonCheckByokConfigResult;
|
|
254
320
|
list_plugins: DaemonListPluginsResult;
|
|
321
|
+
validate_plugins: DaemonValidatePluginsResult;
|
|
322
|
+
setproxy: DaemonSetProxyResult;
|
|
255
323
|
get_usage_info: DaemonGetUsageInfoResult;
|
|
256
324
|
account_info: DaemonAccountInfoResult;
|
|
257
325
|
}
|
|
@@ -4,7 +4,7 @@ import type { QueryTransportProvider } from '../core/transport.js';
|
|
|
4
4
|
import type { DaemonGetModelsParams, DaemonValidateByokModelParams } from './protocol.js';
|
|
5
5
|
import type { BYOKProviderInfo, ByokConfigCheckResult, ByokConfigInfo, ByokConfigReference, CheckByokConfigInput, CreateByokConfigInput, DeleteByokConfigInput, UpdateByokConfigInput } from '../protocol/control.js';
|
|
6
6
|
import type { AccountInfo, ModelInfo, UsageInfo } from '../protocol/common.js';
|
|
7
|
-
import type { PluginDetails } from '../types/plugins.js';
|
|
7
|
+
import type { PluginDetails, PluginValidationReport } from '../types/plugins.js';
|
|
8
8
|
export type DaemonState = 'ready' | 'stopping' | 'stopped' | 'failed';
|
|
9
9
|
export type SessionRuntimeState = 'pending' | 'ready' | 'inactive' | 'failed';
|
|
10
10
|
export interface DaemonSessionInfo {
|
|
@@ -16,21 +16,52 @@ export interface DaemonSessionInfo {
|
|
|
16
16
|
updatedAt: string;
|
|
17
17
|
}
|
|
18
18
|
export interface StartDaemonOptions {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Credentials for the daemon's own account plane and its in-process Sessions.
|
|
21
|
+
*
|
|
22
|
+
* **Optional.** When omitted the daemon starts in the "no credentials" state:
|
|
23
|
+
* the handshake does no identity work, and auth-needing calls answer
|
|
24
|
+
* `AUTH_PAYLOAD_REQUIRED` until you supply credentials via `daemon.auth(payload)`.
|
|
25
|
+
* When provided it is validated (shape) at the handshake and landed lazily on the
|
|
26
|
+
* first auth-needing consumer — never blocking `startDaemon` on the login network.
|
|
27
|
+
*/
|
|
28
|
+
auth?: InternalAuthOptions;
|
|
22
29
|
/**
|
|
23
30
|
* Budget for the `daemon.initialize` round trip; defaults to 30s.
|
|
24
31
|
*
|
|
25
|
-
* The
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
32
|
+
* The handshake only validates the credential payload (when `auth` is given at
|
|
33
|
+
* all — it is optional) and installs the session plane; no auth network happens
|
|
34
|
+
* inside it. The CLI lands the credentials **on demand**: the first auth-needing
|
|
35
|
+
* call (an account-level query, a session's first inference, or an explicit
|
|
36
|
+
* `daemon.auth()`) starts the login. This budget therefore covers CLI startup and
|
|
37
|
+
* the handshake I/O only. Note that host-callback credential requests
|
|
38
|
+
* (`daemon.auth.fetch_job_token` / `fetch_service_account_token`) can arrive
|
|
39
|
+
* at any later point, whenever something first triggers the landing.
|
|
30
40
|
*/
|
|
31
41
|
initializeTimeoutMs?: number;
|
|
32
42
|
pathToQoderCLIExecutable?: string;
|
|
43
|
+
/**
|
|
44
|
+
* 运行 CLI 脚本入口的解释器(node/bun/deno 等),语义与 `query()` 的
|
|
45
|
+
* `Options.executable` 一致:只在解析出的 CLI 入口是脚本文件(.js/.mjs/.ts/...)
|
|
46
|
+
* 时生效,原生二进制忽略它。缺省用宿主 SDK 的 `process.execPath`——原生平台
|
|
47
|
+
* 把随包 Node 传在这里(`executable: runtime.interpreterPath` 配
|
|
48
|
+
* `pathToQoderCLIExecutable: runtime.executablePath`)。
|
|
49
|
+
*/
|
|
50
|
+
executable?: string;
|
|
51
|
+
/** 解释器参数,插在 CLI 脚本路径之前;语义同 `Options.executableArgs`。 */
|
|
52
|
+
executableArgs?: string[];
|
|
53
|
+
/**
|
|
54
|
+
* daemon 进程级代理:握手时随 `daemon.initialize` 写入,作用于该 daemon 的
|
|
55
|
+
* 账号面与所有会话(`daemon_proxy_v1`)。运行期可用 `daemon.setProxy()` 切换。
|
|
56
|
+
*/
|
|
33
57
|
proxy?: string;
|
|
58
|
+
/**
|
|
59
|
+
* VPC private-deployment endpoint for the daemon process (CN deployments only).
|
|
60
|
+
* Written to `QODERCN_VPC_ENDPOINT` / `QODER_VPC_ENDPOINT` before spawn; the CLI
|
|
61
|
+
* reads that environment variable ahead of `settings.json`'s vpcInstanceName.
|
|
62
|
+
* Sessions share the daemon process, so this is not a per-Query option.
|
|
63
|
+
*/
|
|
64
|
+
vpcEndpoint?: string;
|
|
34
65
|
env?: Record<string, string | undefined>;
|
|
35
66
|
/**
|
|
36
67
|
* daemon 子进程 stderr 的实时回调。
|
|
@@ -53,6 +84,11 @@ export interface StartDaemonOptions {
|
|
|
53
84
|
}
|
|
54
85
|
export interface Daemon {
|
|
55
86
|
readonly state: DaemonState;
|
|
87
|
+
/**
|
|
88
|
+
* 订阅连接/进程级失败(与 DaemonImpl 内部 acceptDaemonFailure 同源)。全局槽位靠它
|
|
89
|
+
* 感知「活跃 daemon 已死」并触发重建;普通调用方不需要订阅。返回取消订阅句柄。
|
|
90
|
+
*/
|
|
91
|
+
onFailure(listener: (error: Error) => void): () => void;
|
|
56
92
|
/**
|
|
57
93
|
* 列出会话。`cwd` 给定时只列该工作目录名下的会话;缺省时返回所有目录的全部会话
|
|
58
94
|
* (daemon 无 cwd 概念,「不传目录」即「不过滤」,由 CLI 侧全量扫盘)。
|
|
@@ -66,10 +102,51 @@ export interface Daemon {
|
|
|
66
102
|
/** 删除会话。`cwd` 语义同 renameSession。 */
|
|
67
103
|
deleteSession(localSessionId: string, cwd?: string): Promise<void>;
|
|
68
104
|
/**
|
|
69
|
-
*
|
|
70
|
-
*
|
|
71
|
-
* `
|
|
72
|
-
|
|
105
|
+
* Set or clear the daemon-level (process-wide) proxy for every Session.
|
|
106
|
+
* `undefined` / `null` / an empty string clears it. Requires
|
|
107
|
+
* `daemon_proxy_v1`; resolves with the normalized proxy (or null).
|
|
108
|
+
*/
|
|
109
|
+
setProxy(proxy?: string | null): Promise<string | null>;
|
|
110
|
+
/**
|
|
111
|
+
* The daemon-level proxy currently in effect (`null` when unset/cleared, or
|
|
112
|
+
* when the CLI does not support `daemon_proxy_v1`).
|
|
113
|
+
*/
|
|
114
|
+
getProxy(): string | null;
|
|
115
|
+
/**
|
|
116
|
+
* Explicitly lands credentials and reports whether the daemon is authenticated.
|
|
117
|
+
*
|
|
118
|
+
* The `daemon.initialize` handshake only *validates* the credential payload (and
|
|
119
|
+
* `StartDaemonOptions.auth` is optional); the CLI lands it **on demand** — the
|
|
120
|
+
* first auth-needing call (an account-level query, or a session's first inference)
|
|
121
|
+
* triggers the login implicitly.
|
|
122
|
+
*
|
|
123
|
+
* - `auth()` (no argument): authenticate with the credentials the daemon already
|
|
124
|
+
* holds (from `startDaemon`). Rejects with `AUTH_PAYLOAD_REQUIRED` if it holds
|
|
125
|
+
* none. Idempotent: concurrent and repeated calls share one landing.
|
|
126
|
+
* - `auth(payload)`: **override** the held credentials with `payload`, then
|
|
127
|
+
* authenticate. Use it to supply credentials to a daemon started without auth,
|
|
128
|
+
* or to switch accounts on an already-authenticated daemon. A host-callback arm
|
|
129
|
+
* (`jobToken` / `serviceAccount` token provider) rebinds the reverse-request
|
|
130
|
+
* bridge so the daemon's token fetch reaches the new callback. The override also
|
|
131
|
+
* updates the credentials a later `query({ daemon })` reuses.
|
|
132
|
+
*
|
|
133
|
+
* Resolves `false` for a non-fatal "no credential" outcome (e.g. the read-only
|
|
134
|
+
* borrow of the local qodercli login found nothing). Rejected credentials reject
|
|
135
|
+
* this promise with a `DaemonRpcError` carrying the CLI's error code — never a
|
|
136
|
+
* silent `false`.
|
|
137
|
+
*/
|
|
138
|
+
auth(payload?: InternalAuthOptions): Promise<boolean>;
|
|
139
|
+
/**
|
|
140
|
+
* Account-level queries, answered from the daemon's own credentials — never
|
|
141
|
+
* from a Session's. `daemon_queries_v1` is always negotiated, so these are
|
|
142
|
+
* always callable; each answer depends on the daemon's auth state:
|
|
143
|
+
* authenticated → the data; pending (holds credentials, not yet landed) →
|
|
144
|
+
* triggers the landing then answers; no credentials → `AUTH_PAYLOAD_REQUIRED`
|
|
145
|
+
* (call `auth(payload)` first).
|
|
146
|
+
*
|
|
147
|
+
* Auth-needing queries trigger the credential landing on demand, so the first
|
|
148
|
+
* one may be as slow as a login; `getModels`' cache path answers without
|
|
149
|
+
* credentials and does not trigger it.
|
|
73
150
|
*
|
|
74
151
|
* Unlike the per-`Query` equivalents these do not swallow failures into
|
|
75
152
|
* `null`: capability is already negotiated here, so a rejection is a real
|
|
@@ -84,6 +161,19 @@ export interface Daemon {
|
|
|
84
161
|
deleteByokConfig(target: DeleteByokConfigInput): Promise<void>;
|
|
85
162
|
checkByokConfig(input: CheckByokConfigInput): Promise<ByokConfigCheckResult>;
|
|
86
163
|
listPlugins(): Promise<PluginDetails[]>;
|
|
164
|
+
/**
|
|
165
|
+
* Whether the daemon advertised `capability` in the initialize result.
|
|
166
|
+
* Capabilities are negotiated once per connection and never change.
|
|
167
|
+
*/
|
|
168
|
+
supportsCapability(capability: string): boolean;
|
|
169
|
+
/**
|
|
170
|
+
* Statically validates local plugins in-process (no Session, no auth).
|
|
171
|
+
* Requires `daemon_validate_plugins_v1`; older daemons reject with a
|
|
172
|
+
* `DaemonProtocolError` and callers should fall back to the Worker path.
|
|
173
|
+
*/
|
|
174
|
+
validatePlugins(paths: readonly string[], options?: {
|
|
175
|
+
configDir?: string;
|
|
176
|
+
}): Promise<PluginValidationReport[]>;
|
|
87
177
|
getUsageInfo(): Promise<UsageInfo | null>;
|
|
88
178
|
accountInfo(): Promise<AccountInfo>;
|
|
89
179
|
stop(): Promise<void>;
|
|
@@ -95,7 +185,19 @@ interface InternalDaemonRuntime {
|
|
|
95
185
|
cliPath?: string;
|
|
96
186
|
env?: Record<string, string | undefined>;
|
|
97
187
|
};
|
|
98
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Credentials a daemon-bound `query()` reuses for its Session. Optional: a daemon
|
|
190
|
+
* started without auth has none until `daemon.auth(payload)` supplies them — that
|
|
191
|
+
* call updates this field so a later `query({ daemon })` sees the credentials
|
|
192
|
+
* instead of tripping query()'s "auth is required" client-side gate. Mutable for
|
|
193
|
+
* exactly that reason.
|
|
194
|
+
*/
|
|
195
|
+
auth?: InternalAuthOptions;
|
|
196
|
+
/**
|
|
197
|
+
* The daemon-level proxy currently applied by the CLI (`null` when unset or
|
|
198
|
+
* when the CLI ignored the handshake proxy). Updated by `setProxy`.
|
|
199
|
+
*/
|
|
200
|
+
proxy: string | null;
|
|
99
201
|
readonly transportProvider: QueryTransportProvider<ProcessTransportOptions>;
|
|
100
202
|
}
|
|
101
203
|
export declare function getDaemonRuntime(daemon: Daemon): InternalDaemonRuntime | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -59,7 +59,8 @@ export { initDaemon, shutdownDaemon } from './daemon/global-daemon.js';
|
|
|
59
59
|
export type { DaemonFallbackReason, DaemonInitResult, InitDaemonOptions, } from './daemon/global-daemon.js';
|
|
60
60
|
export { startDaemon } from './daemon/start-daemon.js';
|
|
61
61
|
export type { Daemon, DaemonState, DaemonSessionInfo, SessionRuntimeState, StartDaemonOptions, } from './daemon/start-daemon.js';
|
|
62
|
-
export type { DaemonGetModelsParams, DaemonValidateByokModelParams, } from './daemon/protocol.js';
|
|
62
|
+
export type { DaemonGetModelsParams, DaemonValidateByokModelParams, DaemonValidatePluginsParams, DaemonSetProxyParams, } from './daemon/protocol.js';
|
|
63
|
+
export { DAEMON_PROXY_CAPABILITY, DAEMON_VALIDATE_PLUGINS_CAPABILITY, } from './daemon/protocol.js';
|
|
63
64
|
export { DEFAULT_RUNTIME_TRANSPORT, } from './core/default-runtime.js';
|
|
64
65
|
export { ProcessTransport, QoderCliProcessError, } from './core/process-transport.js';
|
|
65
66
|
export { hasResolvableQoderWorkerRuntime, QoderWorkerRuntimeError, WorkerTransport, resolveQoderWorkerRuntimePath, } from './core/worker-transport.js';
|
|
@@ -75,13 +76,14 @@ export { importSessionToStore } from './session/session-import.js';
|
|
|
75
76
|
export type { ImportSessionToStoreOptions } from './session/session-import.js';
|
|
76
77
|
export type { SessionKey, SessionStore, SessionStoreEntry, SessionStoreFlush, } from './session/session-store.js';
|
|
77
78
|
export { listPlugins, enablePlugin, disablePlugin, installPlugin, uninstallPlugin, validatePlugin, } from './global/plugins.js';
|
|
78
|
-
export type { PluginScope, ListPluginsOptions, PluginToggleOptions, InstallPluginOptions, UninstallPluginOptions, PluginDetails, PluginResources, InstallPluginResult, UninstallPluginResult, PluginValidationSeverity, PluginValidationPhase, PluginValidationPosition, PluginValidationLocation, PluginValidationDiagnostic, PluginValidationReport, ValidatePluginOptions, } from './types/plugins.js';
|
|
79
|
+
export type { PluginScope, ListPluginsOptions, PluginToggleOptions, InstallPluginOptions, UninstallPluginOptions, PluginDetails, PluginResources, InstallPluginResult, UninstallPluginResult, PluginValidationSeverity, PluginValidationPhase, PluginValidationPosition, PluginValidationLocation, PluginValidationDiagnostic, PluginValidationReport, PluginValidationDaemon, ValidatePluginOptions, } from './types/plugins.js';
|
|
79
80
|
export { submitFeedback } from './feedback.js';
|
|
80
81
|
export type { SubmitFeedbackParams, SubmitFeedbackOptions, IntegrationMode, } from './feedback.js';
|
|
81
82
|
export type { HostActionOptions, HostActionParams } from './types/host-action.js';
|
|
82
83
|
export type { HostAction, HostActionEvent, } from './protocol/feedback.js';
|
|
83
84
|
export { AbortError, ControlRequestError, CONTROL_REQUEST_TIMEOUT_CODE, FrameTooLargeError, QoderCliInitializationError, ModelPolicyTimeoutError, ProtocolVersionMismatchError, UnsupportedCliCapabilityError, } from './core/errors.js';
|
|
84
|
-
export { DaemonRpcError } from './daemon/daemon-connection.js';
|
|
85
|
+
export { DaemonRpcError, DaemonSessionAlreadyOpenError, } from './daemon/daemon-connection.js';
|
|
86
|
+
export { DaemonHeartbeatTimeoutError, DAEMON_HEARTBEAT_TIMEOUT_MS, } from './daemon/daemon-connection.js';
|
|
85
87
|
export { AuthAccessTokenEnvVarError, AuthServiceAccountEnvVarError, } from './core/runtime-launch-options.js';
|
|
86
88
|
export { WIRE_PROTOCOL_VERSION } from './protocol/version.js';
|
|
87
89
|
export type { ModelPromptPatch, ModelPromptPatches, } from './protocol/model-prompt-patches.js';
|