dsh-session-bridge 0.3.0 → 0.3.2-alpha.1
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 +18 -1
- package/README.zh.md +16 -0
- package/dsh.plugin.json +2 -2
- package/lib/index.js +498 -89
- package/package.json +21 -20
- package/scripts/build.sh +18 -0
- package/scripts/check-dsh-compat.mjs +173 -0
- package/src/core.ts +77 -13
- package/src/tools.ts +30 -18
package/lib/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { homedir } from "node:os";
|
|
|
4
4
|
import { dirname, join, resolve } from "node:path";
|
|
5
5
|
import { appendFileSync, mkdirSync } from "node:fs";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.
|
|
7
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-home-paths@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-home-paths/lib/index.js
|
|
8
8
|
/**
|
|
9
9
|
* Shared filesystem path helpers for DeepSeek Harness user data.
|
|
10
10
|
*
|
|
@@ -2200,7 +2200,7 @@ var Service = class Service {
|
|
|
2200
2200
|
}
|
|
2201
2201
|
};
|
|
2202
2202
|
//#endregion
|
|
2203
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.
|
|
2203
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-typert-protocol@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-typert-protocol/lib/index.js
|
|
2204
2204
|
/** The one Remote failure class shared by owners, the Gateway, and consumers. */
|
|
2205
2205
|
/**
|
|
2206
2206
|
* One Remote call failure: a real Error carrying its stable code and typed
|
|
@@ -2345,7 +2345,7 @@ function validateName(subject, value) {
|
|
|
2345
2345
|
if (!isTypertRemoteSegment(value)) throw new TypeError(`typert-protocol: ${subject} must contain only RPC endpoint segment characters`);
|
|
2346
2346
|
}
|
|
2347
2347
|
//#endregion
|
|
2348
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.
|
|
2348
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-values@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-values/lib/index.js
|
|
2349
2349
|
/** Duplicate-install-safe JSON and immutable-value helpers. @module @deepseek-ai/dsh-util-values */
|
|
2350
2350
|
/**
|
|
2351
2351
|
* Mark an unreachable closed-union branch.
|
|
@@ -2557,7 +2557,7 @@ function deepFreeze(value) {
|
|
|
2557
2557
|
return value;
|
|
2558
2558
|
}
|
|
2559
2559
|
//#endregion
|
|
2560
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.
|
|
2560
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-util-crypto@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-util-crypto/lib/index.js
|
|
2561
2561
|
/**
|
|
2562
2562
|
* Random v4 UUID, minted from `crypto.getRandomValues`.
|
|
2563
2563
|
* @returns the UUID string.
|
|
@@ -2570,16 +2570,16 @@ function randomUUID$1() {
|
|
|
2570
2570
|
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
2571
2571
|
}
|
|
2572
2572
|
//#endregion
|
|
2573
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.
|
|
2573
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-brand@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-brand/lib/index.js
|
|
2574
2574
|
/**
|
|
2575
|
-
* Duplicate-install-safe nominal
|
|
2575
|
+
* Duplicate-install-safe nominal primitive helpers.
|
|
2576
2576
|
*
|
|
2577
|
-
* A brand makes structurally
|
|
2578
|
-
* level: a `SessionId` cannot be passed where a `ToolCallId` is
|
|
2579
|
-
*
|
|
2580
|
-
* serialization
|
|
2577
|
+
* A brand makes structurally identical strings or numbers non-interchangeable
|
|
2578
|
+
* at the type level: a `SessionId` cannot be passed where a `ToolCallId` is
|
|
2579
|
+
* expected, and an event sequence cannot be passed as a log offset. Comparison,
|
|
2580
|
+
* logging, and serialization retain the underlying primitive behavior.
|
|
2581
2581
|
*
|
|
2582
|
-
* This package owns no concrete
|
|
2582
|
+
* This package owns no concrete domain value and keeps no runtime identity or mutable
|
|
2583
2583
|
* state, so independently installed copies produce interchangeable values.
|
|
2584
2584
|
*
|
|
2585
2585
|
* @module @deepseek-ai/dsh-brand
|
|
@@ -3187,11 +3187,19 @@ defineMethod("transform", [
|
|
|
3187
3187
|
"preserve"
|
|
3188
3188
|
], ({ inner }, isInner) => inner.toString(isInner));
|
|
3189
3189
|
//#endregion
|
|
3190
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.
|
|
3190
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-timeout@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-timeout/lib/index.js
|
|
3191
3191
|
/** Largest delay Node schedules without clamping it to one millisecond. */
|
|
3192
3192
|
const MAX_TIMER_DELAY_MS = 2147483647;
|
|
3193
3193
|
//#endregion
|
|
3194
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.
|
|
3194
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-llm@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-llm/lib/index.js
|
|
3195
|
+
/**
|
|
3196
|
+
* Bound one `notice` summary to {@link CONTEXT_SUMMARY_MAX_CHARS}.
|
|
3197
|
+
* @param summary - the producer's one-line account, of any length.
|
|
3198
|
+
* @returns the account, ellipsized when it exceeds the bound.
|
|
3199
|
+
*/
|
|
3200
|
+
function boundContextSummary(summary) {
|
|
3201
|
+
return summary.length <= 120 ? summary : `${summary.slice(0, 119)}…`;
|
|
3202
|
+
}
|
|
3195
3203
|
/**
|
|
3196
3204
|
* Detach and deep-freeze a message whose identity already exists.
|
|
3197
3205
|
* @param message - complete message, including its stable identity.
|
|
@@ -3433,13 +3441,15 @@ function failureSnapshot(value) {
|
|
|
3433
3441
|
const status = candidate.status;
|
|
3434
3442
|
const providerRetryAfterMs = candidate.providerRetryAfterMs;
|
|
3435
3443
|
const requestId = candidate.requestId;
|
|
3436
|
-
|
|
3444
|
+
const offloadImages = candidate.offloadImages;
|
|
3445
|
+
if (typeof message !== "string" || message.length === 0 || typeof code !== "string" || code.length === 0 || status !== void 0 && (!Number.isInteger(status) || status < 100 || status > 599) || providerRetryAfterMs !== void 0 && (!Number.isFinite(providerRetryAfterMs) || providerRetryAfterMs <= 0) || requestId !== void 0 && (typeof requestId !== "string" || requestId.length === 0) || offloadImages !== void 0 && (!Number.isSafeInteger(offloadImages) || offloadImages <= 0)) return void 0;
|
|
3437
3446
|
return Object.freeze({
|
|
3438
3447
|
message,
|
|
3439
3448
|
code,
|
|
3440
3449
|
...status === void 0 ? {} : { status },
|
|
3441
3450
|
...providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs },
|
|
3442
|
-
...requestId === void 0 ? {} : { requestId }
|
|
3451
|
+
...requestId === void 0 ? {} : { requestId },
|
|
3452
|
+
...offloadImages === void 0 ? {} : { offloadImages }
|
|
3443
3453
|
});
|
|
3444
3454
|
} catch (_sdkFailureGetter) {
|
|
3445
3455
|
return;
|
|
@@ -3457,6 +3467,9 @@ function errorMessage$1(error) {
|
|
|
3457
3467
|
function harnessErrorCode(error) {
|
|
3458
3468
|
return error instanceof HarnessError ? error.code : "UNKNOWN";
|
|
3459
3469
|
}
|
|
3470
|
+
function quoted(value) {
|
|
3471
|
+
return JSON.stringify(value);
|
|
3472
|
+
}
|
|
3460
3473
|
/**
|
|
3461
3474
|
* Stable text shown to a model that cannot accept one durable image reference.
|
|
3462
3475
|
* @param ref - durable normalized attachment omitted from the request.
|
|
@@ -3476,6 +3489,76 @@ function textOnlyImageText(ref) {
|
|
|
3476
3489
|
function contentHasImage(content) {
|
|
3477
3490
|
return content.some((block) => block.type === "image" || block.type === "tool-result" && contentHasImage(block.content));
|
|
3478
3491
|
}
|
|
3492
|
+
/**
|
|
3493
|
+
* True when typed model content contains a file block, walking nested
|
|
3494
|
+
* tool-result content on the same recursion every file policy shares.
|
|
3495
|
+
* Reads current content on every call without retaining scan results.
|
|
3496
|
+
* @param content - typed model content blocks.
|
|
3497
|
+
* @returns whether any nested block is a file.
|
|
3498
|
+
*/
|
|
3499
|
+
function contentHasFile(content) {
|
|
3500
|
+
for (const block of content) if (block.type === "file" || block.type === "tool-result" && contentHasFile(block.content)) return true;
|
|
3501
|
+
return false;
|
|
3502
|
+
}
|
|
3503
|
+
/**
|
|
3504
|
+
* Stable model-facing handle for one durable file reference: the address of
|
|
3505
|
+
* the verbatim stored copy and the instruction to read it on demand. This is
|
|
3506
|
+
* the only representation a provider ever receives for a file.
|
|
3507
|
+
* @param ref - durable verbatim file reference.
|
|
3508
|
+
* @param readonlyPath - execution-world path of the stored copy, when resolvable.
|
|
3509
|
+
* @returns deterministic handle text naming the file, its size, and its address.
|
|
3510
|
+
*/
|
|
3511
|
+
function fileHandleText(ref, readonlyPath) {
|
|
3512
|
+
const digest = String(ref.attachmentId).slice(7, 15);
|
|
3513
|
+
const identity = `File ${quoted(ref.name)} (${ref.bytes} bytes, sha256:${digest})`;
|
|
3514
|
+
if (readonlyPath === void 0) return `[${identity} was uploaded, but the current execution environment cannot access a readable path. Report that limitation if its contents are needed; do not claim to have read it.]`;
|
|
3515
|
+
return `[${identity}: verbatim read-only copy saved at ${quoted(readonlyPath)}. Read that path with your file tools when its contents are needed; copy it to a writable location before modifying it. When delegating file work, include this saved path in the delegation prompt; only subagents sharing this execution environment can read it.]`;
|
|
3516
|
+
}
|
|
3517
|
+
/** Replace every file occurrence, including nested tool results, with handle text. */
|
|
3518
|
+
function replaceFilesWithHandles(blocks, resolvePath) {
|
|
3519
|
+
let next;
|
|
3520
|
+
for (const [index, block] of blocks.entries()) {
|
|
3521
|
+
if (block.type === "file") {
|
|
3522
|
+
next ??= blocks.slice(0, index);
|
|
3523
|
+
next.push({
|
|
3524
|
+
type: "text",
|
|
3525
|
+
text: fileHandleText(block.attachment, resolvePath(block.attachment))
|
|
3526
|
+
});
|
|
3527
|
+
continue;
|
|
3528
|
+
}
|
|
3529
|
+
if (block.type === "tool-result") {
|
|
3530
|
+
const content = replaceFilesWithHandles(block.content, resolvePath);
|
|
3531
|
+
if (content !== block.content) {
|
|
3532
|
+
next ??= blocks.slice(0, index);
|
|
3533
|
+
next.push({
|
|
3534
|
+
...block,
|
|
3535
|
+
content
|
|
3536
|
+
});
|
|
3537
|
+
continue;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
next?.push(block);
|
|
3541
|
+
}
|
|
3542
|
+
return next ?? blocks;
|
|
3543
|
+
}
|
|
3544
|
+
/**
|
|
3545
|
+
* Project durable file history into deterministic handle text for every model
|
|
3546
|
+
* route. Unlike images, no provider receives file blocks natively, so this
|
|
3547
|
+
* projection is unconditional in request assembly.
|
|
3548
|
+
* @param messages - complete request history.
|
|
3549
|
+
* @param resolvePath - resolve one reference's current execution-world read path.
|
|
3550
|
+
* @returns the original list without files, otherwise shallow message copies with handle text.
|
|
3551
|
+
*/
|
|
3552
|
+
function projectFilesToText(messages, resolvePath) {
|
|
3553
|
+
if (!messages.some((message) => contentHasFile(message.content))) return messages;
|
|
3554
|
+
return messages.map((message) => {
|
|
3555
|
+
const content = replaceFilesWithHandles(message.content, resolvePath);
|
|
3556
|
+
return content === message.content ? message : {
|
|
3557
|
+
...message,
|
|
3558
|
+
content
|
|
3559
|
+
};
|
|
3560
|
+
});
|
|
3561
|
+
}
|
|
3479
3562
|
/** Replace every image occurrence, including nested tool results, for a text-only model. */
|
|
3480
3563
|
function replaceImagesForTextModel(blocks) {
|
|
3481
3564
|
let next;
|
|
@@ -3605,7 +3688,8 @@ var LlmError = class extends HarnessError {
|
|
|
3605
3688
|
code,
|
|
3606
3689
|
...options?.status === void 0 ? {} : { status: options.status },
|
|
3607
3690
|
...options?.providerRetryAfterMs === void 0 ? {} : { providerRetryAfterMs: options.providerRetryAfterMs },
|
|
3608
|
-
...options?.requestId === void 0 ? {} : { requestId: options.requestId }
|
|
3691
|
+
...options?.requestId === void 0 ? {} : { requestId: options.requestId },
|
|
3692
|
+
...options?.offloadImages === void 0 ? {} : { offloadImages: options.offloadImages }
|
|
3609
3693
|
});
|
|
3610
3694
|
}
|
|
3611
3695
|
};
|
|
@@ -3916,6 +4000,15 @@ var LlmError = class extends HarnessError {
|
|
|
3916
4000
|
imageRequestPricing(provider, model) {
|
|
3917
4001
|
return this.adapters.get(provider)?.adapter.imageRequestPricing(provider, model);
|
|
3918
4002
|
}
|
|
4003
|
+
/**
|
|
4004
|
+
* Resolve the exact text one durable file occurrence contributes to every
|
|
4005
|
+
* provider request in the current execution environment.
|
|
4006
|
+
* @param ref - durable verbatim file reference from model history.
|
|
4007
|
+
* @returns the same deterministic handle text used at adapter dispatch.
|
|
4008
|
+
*/
|
|
4009
|
+
fileRequestText(ref) {
|
|
4010
|
+
return fileHandleText(ref, this.fileReadPath(ref));
|
|
4011
|
+
}
|
|
3919
4012
|
/** Detach typed adapter-owned modality metadata. */
|
|
3920
4013
|
detachedModalities(modalities) {
|
|
3921
4014
|
return modalities === void 0 ? void 0 : [...modalities];
|
|
@@ -3965,6 +4058,8 @@ var LlmError = class extends HarnessError {
|
|
|
3965
4058
|
const context = resolved.context;
|
|
3966
4059
|
if (context !== void 0 && (!Number.isInteger(context.contextWindow) || context.contextWindow <= 0)) throw new LlmError(`adapter returned invalid context metadata for provider "${provider}" model "${model}"`, "INVALID_MODEL_CONTEXT");
|
|
3967
4060
|
const inputModalities = this.detachedModalities(resolved.inputModalities);
|
|
4061
|
+
const systemPromptUpdate = resolved.systemPromptUpdate;
|
|
4062
|
+
if (systemPromptUpdate !== void 0 && systemPromptUpdate !== "in-history") throw new LlmError(`adapter returned invalid system prompt update mode for provider "${provider}" model "${model}"`, "INVALID_MODEL_INFO");
|
|
3968
4063
|
const defaultMaxTokens = resolved.defaultMaxTokens;
|
|
3969
4064
|
if (defaultMaxTokens !== void 0 && (!Number.isSafeInteger(defaultMaxTokens) || defaultMaxTokens <= 0)) throw new LlmError(`adapter returned invalid default maxTokens for provider "${provider}" model "${model}"`, "INVALID_MODEL_MAX_TOKENS");
|
|
3970
4065
|
const info = {
|
|
@@ -3974,7 +4069,8 @@ var LlmError = class extends HarnessError {
|
|
|
3974
4069
|
...resolved.description === void 0 ? {} : { description: resolved.description },
|
|
3975
4070
|
...inputModalities === void 0 ? {} : { inputModalities },
|
|
3976
4071
|
...context === void 0 ? {} : { context: { contextWindow: context.contextWindow } },
|
|
3977
|
-
...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens }
|
|
4072
|
+
...defaultMaxTokens === void 0 ? {} : { defaultMaxTokens },
|
|
4073
|
+
...resolved.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: resolved.systemPromptUpdate }
|
|
3978
4074
|
};
|
|
3979
4075
|
const reasoning = resolved.reasoning;
|
|
3980
4076
|
if (reasoning === void 0) return info;
|
|
@@ -4068,6 +4164,7 @@ var LlmError = class extends HarnessError {
|
|
|
4068
4164
|
adapterDefaults,
|
|
4069
4165
|
...context === void 0 ? {} : { context },
|
|
4070
4166
|
...modelInfo.inputModalities === void 0 ? {} : { inputModalities: Object.freeze([...modelInfo.inputModalities]) },
|
|
4167
|
+
...modelInfo.systemPromptUpdate === void 0 ? {} : { systemPromptUpdate: modelInfo.systemPromptUpdate },
|
|
4071
4168
|
stream: (options) => {
|
|
4072
4169
|
if (dispatched) throw new LlmError("a prepared LLM call can only be dispatched once", "INVALID_PREPARED_CALL");
|
|
4073
4170
|
if (!callConfigEquals(options, resolvedConfig)) throw new LlmError("prepared LLM call config changed before adapter dispatch", "INVALID_PREPARED_CALL");
|
|
@@ -4109,6 +4206,20 @@ var LlmError = class extends HarnessError {
|
|
|
4109
4206
|
return Object.isFrozen(options) ? deepFreeze(filtered) : filtered;
|
|
4110
4207
|
}
|
|
4111
4208
|
/**
|
|
4209
|
+
* Resolve the current execution-world read path of one durable file
|
|
4210
|
+
* reference through the mounted attachment and filesystem providers.
|
|
4211
|
+
*/
|
|
4212
|
+
fileReadPath(ref) {
|
|
4213
|
+
let hostPath;
|
|
4214
|
+
try {
|
|
4215
|
+
hostPath = this.ctx.get("attachments")?.fileHostPath(ref);
|
|
4216
|
+
} catch {
|
|
4217
|
+
return;
|
|
4218
|
+
}
|
|
4219
|
+
if (hostPath === void 0) return void 0;
|
|
4220
|
+
return this.ctx.get("fs")?.processPathFromHostPath(hostPath);
|
|
4221
|
+
}
|
|
4222
|
+
/**
|
|
4112
4223
|
* Final adapter boundary. Adapter selection, dispatch, iterator construction,
|
|
4113
4224
|
* and iteration failures become one terminal failure chunk. Middleware and
|
|
4114
4225
|
* downstream consumer failures remain thrown plugin or consumer errors.
|
|
@@ -4139,13 +4250,16 @@ var LlmError = class extends HarnessError {
|
|
|
4139
4250
|
...options,
|
|
4140
4251
|
...resolvedConfig
|
|
4141
4252
|
};
|
|
4142
|
-
|
|
4253
|
+
let projectedMessages = resolvedOptions.messages;
|
|
4254
|
+
if (projectedMessages.some((message) => contentHasFile(message.content))) projectedMessages = projectFilesToText(projectedMessages, (ref) => this.fileReadPath(ref));
|
|
4255
|
+
if (modelInfo.inputModalities !== void 0 && !modelInfo.inputModalities.includes("image") && projectedMessages.some((message) => contentHasImage(message.content))) projectedMessages = projectImagesForTextModel(projectedMessages);
|
|
4256
|
+
const projectedOptions = projectedMessages === resolvedOptions.messages ? resolvedOptions : Object.isFrozen(resolvedOptions) ? deepFreeze({
|
|
4143
4257
|
...resolvedOptions,
|
|
4144
|
-
messages:
|
|
4258
|
+
messages: projectedMessages
|
|
4145
4259
|
}) : {
|
|
4146
4260
|
...resolvedOptions,
|
|
4147
|
-
messages:
|
|
4148
|
-
}
|
|
4261
|
+
messages: projectedMessages
|
|
4262
|
+
};
|
|
4149
4263
|
iterator = dispatch(this.forAdapter(projectedOptions, adapter))[Symbol.asyncIterator]();
|
|
4150
4264
|
} catch (error) {
|
|
4151
4265
|
yield adapterFailureChunk(error, options.signal);
|
|
@@ -8966,7 +9080,7 @@ function superRefine(fn, params) {
|
|
|
8966
9080
|
return /* @__PURE__ */ _superRefine(fn, params);
|
|
8967
9081
|
}
|
|
8968
9082
|
//#endregion
|
|
8969
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.
|
|
9083
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2/node_modules/@deepseek-ai/dsh-storage/lib/index.js
|
|
8970
9084
|
/**
|
|
8971
9085
|
* Backend-facing vocabulary of the storage hub: a backend owns one medium
|
|
8972
9086
|
* (a file-tree root, a database file) and exposes operation groups over it.
|
|
@@ -8977,7 +9091,7 @@ function superRefine(fn, params) {
|
|
|
8977
9091
|
/** Allowed format for unit and table names: safe as a file name and as a SQL identifier segment without escaping. */
|
|
8978
9092
|
const UNIT_NAME_RE = /^[a-z][a-z0-9_]*$/;
|
|
8979
9093
|
//#endregion
|
|
8980
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.
|
|
9094
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-storage-domain@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+ds_404bb44176e435660710548cd6a4e0aa/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js
|
|
8981
9095
|
/**
|
|
8982
9096
|
* Domain declaration vocabulary. A spec object is the single source of a
|
|
8983
9097
|
* domain's identity, layout, and record schemas: the owning package defines
|
|
@@ -9121,6 +9235,27 @@ function sessionEvents(session) {
|
|
|
9121
9235
|
function asEventList(events) {
|
|
9122
9236
|
return Array.isArray(events) ? events : [];
|
|
9123
9237
|
}
|
|
9238
|
+
/**
|
|
9239
|
+
* 读取一个持久化(离线)会话的事件日志与头部元数据。兼容两代 persistence API:
|
|
9240
|
+
* - 旧版:`sessionPersistence.inspect(id)` 直接返回 { events, meta };
|
|
9241
|
+
* - dsh 0.1.5 之后:`inspect` 已删除,改用 `open(id, 'read')` → `handle.read()`
|
|
9242
|
+
* (+ `handle.header`),读句柄不抢写所有权,读后必须 close()。
|
|
9243
|
+
* 会话不存在时两个 API 都抛错,调用方按原语义处理。
|
|
9244
|
+
*/
|
|
9245
|
+
async function inspectPersistedSession(ctx, id) {
|
|
9246
|
+
const persistence = ctx.sessionPersistence;
|
|
9247
|
+
if (typeof persistence.inspect === "function") return await persistence.inspect(id);
|
|
9248
|
+
const handle = await persistence.open(id, "read");
|
|
9249
|
+
try {
|
|
9250
|
+
const { events } = await handle.read();
|
|
9251
|
+
return {
|
|
9252
|
+
events,
|
|
9253
|
+
meta: handle.header
|
|
9254
|
+
};
|
|
9255
|
+
} finally {
|
|
9256
|
+
await handle.close();
|
|
9257
|
+
}
|
|
9258
|
+
}
|
|
9124
9259
|
/** agent.followup / steer 接受的用户消息值。 */
|
|
9125
9260
|
function userMessage(text) {
|
|
9126
9261
|
return {
|
|
@@ -9252,12 +9387,14 @@ function latestSegmentSince(events, sinceSeq = 0) {
|
|
|
9252
9387
|
return segs.length === 0 ? null : segs[segs.length - 1] ?? null;
|
|
9253
9388
|
}
|
|
9254
9389
|
/**
|
|
9255
|
-
* 对一个 live 会话的事件日志折叠出其"
|
|
9256
|
-
* -
|
|
9257
|
-
*
|
|
9258
|
-
* -
|
|
9259
|
-
* -
|
|
9260
|
-
*
|
|
9390
|
+
* 对一个 live 会话的事件日志折叠出其"最近推理/文本增量流"。兼容两代日志形状:
|
|
9391
|
+
* - dsh 0.1.5 之后:turn 内不再发布独立 chunk 事件,流式增量内嵌在已定型
|
|
9392
|
+
* assistant/message(或未定型 assistant/attempt)事件的 `stream` 记录里
|
|
9393
|
+
* (reasoning-chunks / text-chunks 批量段 + 原始 chunk:reasoning-delta / text-delta);
|
|
9394
|
+
* - 0.1.2-rc 之前:独立的 assistant/chunk 事件(turn 中途即可见、增量,
|
|
9395
|
+
* 这正是旧版监控思维链并按规则提前终止所需的粒度)。
|
|
9396
|
+
* 两者兼读、取最新一份;无任何增量(会话空闲、或该 provider 不流式推理/无推理)
|
|
9397
|
+
* 返回 null,调用方应回落为 foldMessages 里已定型的 message.reasoning。
|
|
9261
9398
|
* 纯读、无副作用;事件形状不做任何假设,缺失/异常一律安全处理。
|
|
9262
9399
|
*/
|
|
9263
9400
|
function liveReasoningSnapshot(events) {
|
|
@@ -9271,11 +9408,41 @@ function liveReasoningSnapshot(events) {
|
|
|
9271
9408
|
let step = 0;
|
|
9272
9409
|
let foundDelta = false;
|
|
9273
9410
|
for (const event of list) {
|
|
9274
|
-
|
|
9275
|
-
|
|
9411
|
+
const type = event.type;
|
|
9412
|
+
if (type === "assistant/message" || type === "assistant/attempt") {
|
|
9413
|
+
const data = event.data;
|
|
9414
|
+
if (data !== null && data !== void 0 && typeof data === "object" && Array.isArray(data.stream)) {
|
|
9415
|
+
let r = "";
|
|
9416
|
+
let t = "";
|
|
9417
|
+
for (const raw of data.stream) {
|
|
9418
|
+
const record = raw;
|
|
9419
|
+
if (record === null || typeof record !== "object") continue;
|
|
9420
|
+
if (record.type === "reasoning-chunks" && Array.isArray(record.texts)) {
|
|
9421
|
+
for (const s of record.texts) if (typeof s === "string") r += s;
|
|
9422
|
+
} else if (record.type === "text-chunks" && Array.isArray(record.texts)) {
|
|
9423
|
+
for (const s of record.texts) if (typeof s === "string") t += s;
|
|
9424
|
+
} else if (record.type === "chunk") {
|
|
9425
|
+
const c = record.chunk;
|
|
9426
|
+
if (c !== null && typeof c === "object" && typeof c.type === "string" && typeof c.text === "string") {
|
|
9427
|
+
if (c.type === "reasoning-delta") r += c.text;
|
|
9428
|
+
else if (c.type === "text-delta") t += c.text;
|
|
9429
|
+
}
|
|
9430
|
+
}
|
|
9431
|
+
}
|
|
9432
|
+
if (r !== "" || t !== "") {
|
|
9433
|
+
if (typeof data.turn === "number") turn = data.turn;
|
|
9434
|
+
if (typeof data.step === "number") step = data.step;
|
|
9435
|
+
reasoning = r;
|
|
9436
|
+
text = t;
|
|
9437
|
+
seq = event.seq;
|
|
9438
|
+
time = event.time;
|
|
9439
|
+
foundDelta = true;
|
|
9440
|
+
}
|
|
9441
|
+
}
|
|
9442
|
+
if (type === "assistant/message") lastFinalizedSeq = event.seq;
|
|
9276
9443
|
continue;
|
|
9277
9444
|
}
|
|
9278
|
-
if (
|
|
9445
|
+
if (type !== "assistant/chunk") continue;
|
|
9279
9446
|
if (event.seq <= lastFinalizedSeq) continue;
|
|
9280
9447
|
const data = event.data;
|
|
9281
9448
|
if (data === null || data === void 0 || typeof data !== "object") continue;
|
|
@@ -9511,7 +9678,7 @@ function statusSnapshot(ctx, agent) {
|
|
|
9511
9678
|
lastTurn,
|
|
9512
9679
|
lastActivityAt,
|
|
9513
9680
|
stalledMs: lastActivityAt === null ? null : Date.now() - lastActivityAt,
|
|
9514
|
-
pendingWork: inbox?.hasPending ??
|
|
9681
|
+
pendingWork: inbox?.hasPending === true || (inbox?.nextTurn?.length ?? 0) + (inbox?.nextStep?.length ?? 0) > 0,
|
|
9515
9682
|
nextTurnCount: inbox?.nextTurn?.length ?? 0,
|
|
9516
9683
|
nextStepCount: inbox?.nextStep?.length ?? 0,
|
|
9517
9684
|
...lastAssistantText === void 0 ? {} : { lastAssistantText },
|
|
@@ -9874,7 +10041,7 @@ var SessionMonitor = class {
|
|
|
9874
10041
|
}
|
|
9875
10042
|
};
|
|
9876
10043
|
//#endregion
|
|
9877
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.
|
|
10044
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-scope@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-invaria_eaf7046112a9b60866fe7f69bc8f6f64/node_modules/@deepseek-ai/dsh-scope/lib/index.js
|
|
9878
10045
|
/**
|
|
9879
10046
|
* Shared insertion-ordered storage and effect ownership for scope-aware registries.
|
|
9880
10047
|
*
|
|
@@ -10153,7 +10320,92 @@ function scopeTarget(base, key) {
|
|
|
10153
10320
|
return carrier;
|
|
10154
10321
|
}
|
|
10155
10322
|
//#endregion
|
|
10156
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-
|
|
10323
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-sandbox@0.1.6-alpha.1_@deepseek-ai+cordis@4.0.2_@deepseek-ai+dsh-llm@0_1d3a97f96d2766469566ca2b01247bfa/node_modules/@deepseek-ai/dsh-sandbox/lib/index.js
|
|
10324
|
+
/**
|
|
10325
|
+
* The escalation vocabulary and choreography shared by every sandbox-enforcing
|
|
10326
|
+
* tool family (`@deepseek-ai/dsh-tool-bash`, `@deepseek-ai/dsh-tool-fs`): the
|
|
10327
|
+
* strictly-wider ladder, the argument-pairing validation, the model-facing
|
|
10328
|
+
* denial/hint markers, and {@link approveEscalation} — the ordered fail-closed
|
|
10329
|
+
* sequence that resolves a `sandbox_permissions` request through a
|
|
10330
|
+
* user-approval channel BEFORE anything executes. One home keeps the two
|
|
10331
|
+
* families' approval ordering and verbatim error texts from drifting apart.
|
|
10332
|
+
*
|
|
10333
|
+
* The channel is a minimal STRUCTURAL function shape ({@link EscalationAsk}),
|
|
10334
|
+
* not the approval service type: the tool layer — which owns the agent, the
|
|
10335
|
+
* call id, and the tool name — closes over `ctx.approval.request(...)` and
|
|
10336
|
+
* hands the closure down, so this package never depends on the approval or
|
|
10337
|
+
* agent packages.
|
|
10338
|
+
*
|
|
10339
|
+
* @module dsh-sandbox/escalation
|
|
10340
|
+
*/
|
|
10341
|
+
/**
|
|
10342
|
+
* The strictly-wider table: what a call whose effective mode is the key may
|
|
10343
|
+
* escalate TO. Checked at EXECUTION, never baked into a tool schema — the
|
|
10344
|
+
* schema's enum is {@link ESCALATION_TARGETS}, because schemas are
|
|
10345
|
+
* registry-global while the effective mode is per-call truth.
|
|
10346
|
+
*/
|
|
10347
|
+
const WIDER_MODES = {
|
|
10348
|
+
"read-only": ["workspace-write", "danger-full-access"],
|
|
10349
|
+
"workspace-write": ["danger-full-access"]
|
|
10350
|
+
};
|
|
10351
|
+
/**
|
|
10352
|
+
* The closed escalation-target vocabulary — every mode a call could ever
|
|
10353
|
+
* escalate TO (`read-only` is the floor; nothing escalates to it). Advertised
|
|
10354
|
+
* whenever the mounted capability confines: cutting the enum down to the modes
|
|
10355
|
+
* wider than the composition's DEFAULT would strand a session whose effective
|
|
10356
|
+
* mode sits below it (a `danger-full-access` default would advertise nothing
|
|
10357
|
+
* while a narrower-switched session stays confined with no lever).
|
|
10358
|
+
*/
|
|
10359
|
+
const ESCALATION_TARGETS = ["workspace-write", "danger-full-access"];
|
|
10360
|
+
/**
|
|
10361
|
+
* Validate the escalation argument pairing a tool schema cannot express:
|
|
10362
|
+
* `sandbox_permissions` and `justification` travel together — an approval
|
|
10363
|
+
* prompt without a reason, or a reason driving nothing, is a malformed ask —
|
|
10364
|
+
* and the justification must be a non-empty sentence.
|
|
10365
|
+
* @param sandboxPermissions - the raw `sandbox_permissions` argument, if given.
|
|
10366
|
+
* @param justification - the raw `justification` argument, if given.
|
|
10367
|
+
*/
|
|
10368
|
+
function validateEscalationArgs(sandboxPermissions, justification) {
|
|
10369
|
+
if (sandboxPermissions !== void 0 && justification === void 0) throw new Error("invalid escalation: sandbox_permissions requires a justification");
|
|
10370
|
+
if (justification !== void 0 && sandboxPermissions === void 0) throw new Error("invalid escalation: justification is only valid together with sandbox_permissions");
|
|
10371
|
+
if (justification !== void 0 && justification.trim().length === 0) throw new Error("invalid justification: expected a non-empty sentence");
|
|
10372
|
+
}
|
|
10373
|
+
/**
|
|
10374
|
+
* Resolve a sandbox-escalation request BEFORE anything executes: check strict
|
|
10375
|
+
* widening against the call's effective mode, then resolve the approval
|
|
10376
|
+
* channel, then map every outcome — the ordered fail-closed sequence both
|
|
10377
|
+
* enforcing families share. Returns the granted mode to stamp onto exactly
|
|
10378
|
+
* this call; throws the distinct verbatim text for every other path (a
|
|
10379
|
+
* non-widening request, a missing approval service, an agent-less execution,
|
|
10380
|
+
* a rejection, a cancellation, an unanswerable ask) — the tool registry turns
|
|
10381
|
+
* the throw into the call's isError result, and nothing has run. A
|
|
10382
|
+
* non-widening request never prompts a human.
|
|
10383
|
+
* @param request - the escalation to judge (see {@link EscalationRequest}).
|
|
10384
|
+
* @param approval - the approval ingredients the tool holds (see {@link EscalationApproval}).
|
|
10385
|
+
* @returns the granted mode, consumed by the one call that asked.
|
|
10386
|
+
*/
|
|
10387
|
+
async function approveEscalation(request, approval) {
|
|
10388
|
+
const { requestedMode: mode, effectiveMode, justification, subject } = request;
|
|
10389
|
+
if (!(WIDER_MODES[effectiveMode] ?? []).includes(mode)) throw new Error(`sandbox escalation to "${mode}" is not strictly wider than this call's current "${effectiveMode}" mode`);
|
|
10390
|
+
if (approval.approver === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval service is composed`);
|
|
10391
|
+
if (approval.agent === void 0) throw new Error(`sandbox escalation to "${mode}" requires approval, but the call has no agent to route it through`);
|
|
10392
|
+
const outcome = await approval.approver.request({
|
|
10393
|
+
agent: approval.agent,
|
|
10394
|
+
toolName: approval.toolName,
|
|
10395
|
+
callId: approval.callId,
|
|
10396
|
+
reason: `escalate sandbox to ${mode}: ${justification}`,
|
|
10397
|
+
...approval.signal ? { signal: approval.signal } : {}
|
|
10398
|
+
});
|
|
10399
|
+
switch (outcome) {
|
|
10400
|
+
case "allowed-once": return mode;
|
|
10401
|
+
case "rejected": throw new Error(`the user rejected escalating this ${subject} to "${mode}"`);
|
|
10402
|
+
case "cancelled": throw new Error(`approval for escalating to "${mode}" was cancelled`);
|
|
10403
|
+
case "unavailable": throw new Error(`sandbox escalation to "${mode}" requires approval, but no approval channel is available`);
|
|
10404
|
+
default: return assertNever(outcome, "EscalationOutcome");
|
|
10405
|
+
}
|
|
10406
|
+
}
|
|
10407
|
+
//#endregion
|
|
10408
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-tools@0.1.6-alpha.1_e89197212305e1b19bd6df05221bc44b/node_modules/@deepseek-ai/dsh-tools/lib/index.js
|
|
10157
10409
|
/**
|
|
10158
10410
|
* Enforced JSON Schema subset shared by tool outputs, generated PTC mode
|
|
10159
10411
|
* types, subagents, and workflows. The subset accepts any JSON root, an
|
|
@@ -11024,7 +11276,7 @@ const TYPESCRIPT_FLAVOR = {
|
|
|
11024
11276
|
description: "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return is program output — curate it. Image-bearing subtool results are attached after the run.",
|
|
11025
11277
|
codeDescription: "The program: the body of an async TypeScript function."
|
|
11026
11278
|
};
|
|
11027
|
-
/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link
|
|
11279
|
+
/** Per-language `run_code` schema flavors (see {@link RunCodeFlavor}); one entry per {@link PtcSdkLanguage}. */
|
|
11028
11280
|
const RUN_CODE_FLAVORS = {
|
|
11029
11281
|
typescript: TYPESCRIPT_FLAVOR,
|
|
11030
11282
|
python: {
|
|
@@ -11039,17 +11291,48 @@ const RUN_CODE_FLAVORS = {
|
|
|
11039
11291
|
* can never drift.
|
|
11040
11292
|
*/
|
|
11041
11293
|
const RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION = "Clear, concise description of what this program does in active voice, 5-10 words (shown in the UI). Examples: \"Count TODO markers across packages\"; \"Read failing test and its fixture\"; \"Rename config key in every cordis.yml\".";
|
|
11294
|
+
const RUN_CODE_CONTROLS = {
|
|
11295
|
+
timeoutMs: {
|
|
11296
|
+
type: "number",
|
|
11297
|
+
description: "Positive elapsed-time budget in milliseconds, capped by the deployment maximum."
|
|
11298
|
+
},
|
|
11299
|
+
sandbox_permissions: {
|
|
11300
|
+
type: "string",
|
|
11301
|
+
enum: [...ESCALATION_TARGETS],
|
|
11302
|
+
description: "Wider sandbox mode for this complete program execution; requires justification and approval."
|
|
11303
|
+
},
|
|
11304
|
+
justification: {
|
|
11305
|
+
type: "string",
|
|
11306
|
+
description: "Reason this complete program needs wider access, shown to the user for approval."
|
|
11307
|
+
}
|
|
11308
|
+
};
|
|
11309
|
+
function controlParameters(runtime) {
|
|
11310
|
+
if (runtime === void 0) return RUN_CODE_CONTROLS;
|
|
11311
|
+
return {
|
|
11312
|
+
...runtime.timeout === void 0 ? {} : { timeoutMs: {
|
|
11313
|
+
...RUN_CODE_CONTROLS.timeoutMs,
|
|
11314
|
+
description: `Positive elapsed-time budget in milliseconds, including nested tool and approval waits. Default ${runtime.timeout.defaultMs}; capped at ${runtime.timeout.maxMs}. Zero does not disable the deadline.`
|
|
11315
|
+
} },
|
|
11316
|
+
...runtime.sandboxMode === void 0 ? {} : {
|
|
11317
|
+
sandbox_permissions: RUN_CODE_CONTROLS.sandbox_permissions,
|
|
11318
|
+
justification: RUN_CODE_CONTROLS.justification
|
|
11319
|
+
}
|
|
11320
|
+
};
|
|
11321
|
+
}
|
|
11322
|
+
function escalationGuidance(runtime) {
|
|
11323
|
+
return runtime?.sandboxMode === void 0 ? "" : " A sandbox escalation approves this complete program for one execution only. Nested tools retain their own policies and approvals. Request wider access only after evidence of a denial. Earlier effects may already have completed: inspect them before explicitly retrying. Programs are never replayed automatically.";
|
|
11324
|
+
}
|
|
11042
11325
|
/**
|
|
11043
11326
|
* Resolve the {@link RunCodeFlavor} for the loaded runtime's language, read at
|
|
11044
11327
|
* schema-emission time so the model-visible `run_code` schema always matches
|
|
11045
11328
|
* the SDK section's language. `peekRuntime` returns `undefined` only when no
|
|
11046
11329
|
* runtime is mounted, which reaches this function through definition readers
|
|
11047
11330
|
* and `schemas()` — the doc-catalog harvest is the only shipped one, and none
|
|
11048
|
-
* of them feeds a model, because `wireSchemas` calls `
|
|
11331
|
+
* of them feeds a model, because `wireSchemas` calls `requirePtcRuntime`
|
|
11049
11332
|
* before projecting — so that path degrades to {@link TYPESCRIPT_FLAVOR}. A
|
|
11050
11333
|
* mounted runtime whose language has no flavor entry fails loud, exactly as
|
|
11051
|
-
* `
|
|
11052
|
-
* `SDK_RENDERERS` is the compiler's job ({@link
|
|
11334
|
+
* `requirePtcRuntime` rejects it at assembly. Keeping this table in step with
|
|
11335
|
+
* `SDK_RENDERERS` is the compiler's job ({@link PtcSdkLanguage}); what this
|
|
11053
11336
|
* guard owns is the runtime-supplied language neither table knows, which never
|
|
11054
11337
|
* yields a wrong-language schema for a real runtime.
|
|
11055
11338
|
*/
|
|
@@ -11218,7 +11501,8 @@ function createRunCodeTool(registry, options) {
|
|
|
11218
11501
|
type: "string",
|
|
11219
11502
|
required: true,
|
|
11220
11503
|
description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION
|
|
11221
|
-
}
|
|
11504
|
+
},
|
|
11505
|
+
...RUN_CODE_CONTROLS
|
|
11222
11506
|
},
|
|
11223
11507
|
output: {
|
|
11224
11508
|
schema: {
|
|
@@ -11230,12 +11514,37 @@ function createRunCodeTool(registry, options) {
|
|
|
11230
11514
|
required: true,
|
|
11231
11515
|
items: { type: "string" }
|
|
11232
11516
|
},
|
|
11233
|
-
result: { type: "json" }
|
|
11517
|
+
result: { type: "json" },
|
|
11518
|
+
sandbox: {
|
|
11519
|
+
type: "object",
|
|
11520
|
+
additionalProperties: false,
|
|
11521
|
+
properties: {
|
|
11522
|
+
mode: {
|
|
11523
|
+
type: "string",
|
|
11524
|
+
required: true,
|
|
11525
|
+
enum: [
|
|
11526
|
+
"read-only",
|
|
11527
|
+
"workspace-write",
|
|
11528
|
+
"danger-full-access"
|
|
11529
|
+
]
|
|
11530
|
+
},
|
|
11531
|
+
denied: {
|
|
11532
|
+
type: "boolean",
|
|
11533
|
+
required: true
|
|
11534
|
+
},
|
|
11535
|
+
enforcement: {
|
|
11536
|
+
type: "string",
|
|
11537
|
+
enum: ["full", "partial"]
|
|
11538
|
+
}
|
|
11539
|
+
}
|
|
11540
|
+
}
|
|
11234
11541
|
}
|
|
11235
11542
|
},
|
|
11236
11543
|
render: (_args, value) => {
|
|
11237
11544
|
const rendered = value.result === void 0 ? "" : renderValue(value.result);
|
|
11238
11545
|
const parts = [value.logs.join("\n"), rendered].filter((part) => part.length > 0);
|
|
11546
|
+
if (value.sandbox?.enforcement === "partial") parts.push("File sandbox enforcement is partial on this host.");
|
|
11547
|
+
if (value.sandbox?.denied) parts.push(`The ${value.sandbox.mode} file sandbox denied an operation.${escalationGuidance(peekRuntime())}`);
|
|
11239
11548
|
return [{
|
|
11240
11549
|
type: "text",
|
|
11241
11550
|
text: parts.length > 0 ? parts.join("\n") : "(run_code completed with no output)"
|
|
@@ -11245,6 +11554,31 @@ function createRunCodeTool(registry, options) {
|
|
|
11245
11554
|
async execute(args, exec) {
|
|
11246
11555
|
if (args.description.trim().length === 0) throw new Error("invalid description: expected a non-empty string");
|
|
11247
11556
|
const runtime = requireRuntime();
|
|
11557
|
+
validateEscalationArgs(args.sandbox_permissions, args.justification);
|
|
11558
|
+
if (args.timeoutMs !== void 0 && runtime.timeout === void 0) throw new Error("timeoutMs is not available for this PTC runtime");
|
|
11559
|
+
if (args.timeoutMs !== void 0 && (!Number.isFinite(args.timeoutMs) || args.timeoutMs <= 0)) throw new Error("invalid timeoutMs: expected a positive finite number");
|
|
11560
|
+
const standingPolicy = runtime.sandboxMode === void 0 ? void 0 : options.resolveSandboxPolicy(exec);
|
|
11561
|
+
let policy = standingPolicy;
|
|
11562
|
+
if (args.sandbox_permissions !== void 0 && args.justification !== void 0) {
|
|
11563
|
+
if (standingPolicy === void 0) throw new Error("sandbox_permissions is not available for this PTC runtime");
|
|
11564
|
+
const approvedMode = await approveEscalation({
|
|
11565
|
+
requestedMode: args.sandbox_permissions,
|
|
11566
|
+
justification: args.justification,
|
|
11567
|
+
effectiveMode: standingPolicy.mode,
|
|
11568
|
+
subject: "program"
|
|
11569
|
+
}, {
|
|
11570
|
+
approver: options.peekApprover(),
|
|
11571
|
+
agent: exec.agent,
|
|
11572
|
+
callId: exec.callId,
|
|
11573
|
+
toolName: RUN_CODE_NAME,
|
|
11574
|
+
signal: exec.signal
|
|
11575
|
+
});
|
|
11576
|
+
policy = {
|
|
11577
|
+
...standingPolicy,
|
|
11578
|
+
mode: approvedMode
|
|
11579
|
+
};
|
|
11580
|
+
}
|
|
11581
|
+
exec.signal.throwIfAborted();
|
|
11248
11582
|
const runController = new AbortController();
|
|
11249
11583
|
const onOuterAbort = () => {
|
|
11250
11584
|
runController.abort(exec.signal.reason);
|
|
@@ -11326,15 +11660,17 @@ function createRunCodeTool(registry, options) {
|
|
|
11326
11660
|
while (logWork.size > 0) await Promise.allSettled([...logWork]);
|
|
11327
11661
|
};
|
|
11328
11662
|
const runOver = () => runController.signal.aborted;
|
|
11329
|
-
const binding = (
|
|
11663
|
+
const binding = (schema) => async (rawArgs) => {
|
|
11664
|
+
const { name } = schema;
|
|
11330
11665
|
if (runOver()) throw new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} not dispatched`);
|
|
11331
11666
|
const normalized = jsonNormalizeArgs(rawArgs);
|
|
11332
11667
|
const n = ++dispatches;
|
|
11333
|
-
const subCallId = brandString(`${String(exec.callId)}:
|
|
11668
|
+
const subCallId = brandString(`${String(exec.callId)}:ptc:${n}`);
|
|
11334
11669
|
const input = {
|
|
11335
11670
|
callId: subCallId,
|
|
11336
11671
|
rootCallId: exec.rootCallId,
|
|
11337
11672
|
name,
|
|
11673
|
+
schema,
|
|
11338
11674
|
arguments: normalized.dispatched,
|
|
11339
11675
|
...exec.agent ? { agent: exec.agent } : {},
|
|
11340
11676
|
parent: exec.token,
|
|
@@ -11362,13 +11698,14 @@ function createRunCodeTool(registry, options) {
|
|
|
11362
11698
|
isError: result.isError,
|
|
11363
11699
|
content: result.content
|
|
11364
11700
|
});
|
|
11365
|
-
agent.session.append("tool/
|
|
11701
|
+
agent.session.append("tool/ptc-dispatch", {
|
|
11366
11702
|
rootCallId: exec.rootCallId,
|
|
11367
11703
|
parentCallId: exec.callId,
|
|
11368
11704
|
subCallId,
|
|
11369
11705
|
name,
|
|
11370
11706
|
arguments: normalized.logged,
|
|
11371
11707
|
isError: result.isError,
|
|
11708
|
+
...result.error?.info === void 0 ? {} : { error: result.error.info },
|
|
11372
11709
|
content: logged
|
|
11373
11710
|
});
|
|
11374
11711
|
})().finally(() => {
|
|
@@ -11384,7 +11721,7 @@ function createRunCodeTool(registry, options) {
|
|
|
11384
11721
|
reject(/* @__PURE__ */ new Error(`run_code run is over (${String(runController.signal.reason)}); ${name} tool call abandoned`));
|
|
11385
11722
|
},
|
|
11386
11723
|
async start() {
|
|
11387
|
-
exec.agent?.session.append("tool/
|
|
11724
|
+
exec.agent?.session.append("tool/ptc-dispatch-start", {
|
|
11388
11725
|
rootCallId: exec.rootCallId,
|
|
11389
11726
|
parentCallId: exec.callId,
|
|
11390
11727
|
subCallId,
|
|
@@ -11418,7 +11755,7 @@ function createRunCodeTool(registry, options) {
|
|
|
11418
11755
|
content: result.content,
|
|
11419
11756
|
source: {
|
|
11420
11757
|
kind: "plugin",
|
|
11421
|
-
plugin: "tools-
|
|
11758
|
+
plugin: "tools-ptc"
|
|
11422
11759
|
}
|
|
11423
11760
|
}));
|
|
11424
11761
|
for (const context of result.additionalContexts ?? []) exec.deferContext(context);
|
|
@@ -11439,13 +11776,13 @@ function createRunCodeTool(registry, options) {
|
|
|
11439
11776
|
if (schema.name === "run_code") continue;
|
|
11440
11777
|
Object.defineProperty(functions, schema.name, {
|
|
11441
11778
|
enumerable: true,
|
|
11442
|
-
value: binding(schema
|
|
11779
|
+
value: binding(deepFreeze(schema))
|
|
11443
11780
|
});
|
|
11444
11781
|
}
|
|
11445
11782
|
try {
|
|
11446
11783
|
let result;
|
|
11447
11784
|
try {
|
|
11448
|
-
result = await runtime.run({
|
|
11785
|
+
result = await runtime.run(runtime.resolve({
|
|
11449
11786
|
program: args.code,
|
|
11450
11787
|
bindings: [{
|
|
11451
11788
|
global: "tools",
|
|
@@ -11455,18 +11792,23 @@ function createRunCodeTool(registry, options) {
|
|
|
11455
11792
|
memberNameProperty: "toolName"
|
|
11456
11793
|
}
|
|
11457
11794
|
}],
|
|
11458
|
-
signal: runController.signal
|
|
11459
|
-
|
|
11795
|
+
signal: runController.signal,
|
|
11796
|
+
...exec.agent?.session.header.cwd !== void 0 ? { cwd: exec.agent.session.header.cwd } : {},
|
|
11797
|
+
...policy !== void 0 ? { sandboxPolicy: policy } : {},
|
|
11798
|
+
...args.timeoutMs !== void 0 ? { timeoutMs: args.timeoutMs } : {}
|
|
11799
|
+
}));
|
|
11460
11800
|
} finally {
|
|
11461
11801
|
runController.abort("run_code settled");
|
|
11462
11802
|
await drainDispatches();
|
|
11463
11803
|
}
|
|
11464
11804
|
if (result.error) {
|
|
11465
11805
|
const logsText = result.logs.length > 0 ? `\nCaptured output:\n${result.logs.join("\n")}` : "";
|
|
11466
|
-
|
|
11806
|
+
const sandboxText = result.sandbox === void 0 ? "" : `\nFile sandbox: ${result.sandbox.mode}${result.sandbox.enforcement === void 0 ? "" : `; enforcement: ${result.sandbox.enforcement}`}${result.sandbox.denied ? "; operation denied" : ""}.`;
|
|
11807
|
+
throw new CodeRunFailedError(`code run failed (${result.error.kind}): ${result.error.message}${logsText}${sandboxText}${result.sandbox?.denied ? escalationGuidance(runtime) : ""}`);
|
|
11467
11808
|
}
|
|
11468
11809
|
return {
|
|
11469
11810
|
logs: result.logs,
|
|
11811
|
+
...result.sandbox === void 0 ? {} : { sandbox: result.sandbox },
|
|
11470
11812
|
...result.value !== void 0 ? { result: result.value } : {}
|
|
11471
11813
|
};
|
|
11472
11814
|
} finally {
|
|
@@ -11482,7 +11824,11 @@ function createRunCodeTool(registry, options) {
|
|
|
11482
11824
|
});
|
|
11483
11825
|
Object.defineProperty(definition, "description", {
|
|
11484
11826
|
enumerable: true,
|
|
11485
|
-
get: () =>
|
|
11827
|
+
get: () => {
|
|
11828
|
+
const runtime = peekRuntime();
|
|
11829
|
+
const instructions = runtime?.executionInstructions;
|
|
11830
|
+
return resolveFlavor(peekRuntime).description + (instructions ? ` ${instructions}` : "") + (runtime === void 0 ? "" : " The working directory is the Session's current directory.") + escalationGuidance(runtime);
|
|
11831
|
+
}
|
|
11486
11832
|
});
|
|
11487
11833
|
Object.defineProperty(definition, "parameters", {
|
|
11488
11834
|
enumerable: true,
|
|
@@ -11496,7 +11842,8 @@ function createRunCodeTool(registry, options) {
|
|
|
11496
11842
|
type: "string",
|
|
11497
11843
|
required: true,
|
|
11498
11844
|
description: RUN_CODE_DESCRIPTION_PARAM_DESCRIPTION
|
|
11499
|
-
}
|
|
11845
|
+
},
|
|
11846
|
+
...controlParameters(peekRuntime())
|
|
11500
11847
|
})
|
|
11501
11848
|
});
|
|
11502
11849
|
return definition;
|
|
@@ -11781,7 +12128,7 @@ function renderToolsSdk(schemas) {
|
|
|
11781
12128
|
* PTC mode codegen — Python flavor. The pure projection from registered tool schemas to the
|
|
11782
12129
|
* Python SDK text the model programs against under `runtime.language === 'python'`. Sibling of
|
|
11783
12130
|
* {@link ./ts-types.ts | ts-types.ts}; the two files are two projections of the same registry
|
|
11784
|
-
* store, keyed by the loaded {@link @deepseek-ai/dsh-
|
|
12131
|
+
* store, keyed by the loaded {@link @deepseek-ai/dsh-ptc-runtime#PtcRuntime.language | PTC
|
|
11785
12132
|
* runtime's language}.
|
|
11786
12133
|
*
|
|
11787
12134
|
* Under `mode: 'ptc'` the native tool schemas are omitted from the request, so this generated
|
|
@@ -12468,17 +12815,17 @@ function renderToolsSdkPy(schemas) {
|
|
|
12468
12815
|
*/
|
|
12469
12816
|
/**
|
|
12470
12817
|
* Language → SDK-section renderer. The registry looks up the loaded
|
|
12471
|
-
* `ctx.
|
|
12818
|
+
* `ctx.ptcRuntime.language` in this table when assembling the `tools:sdk`
|
|
12472
12819
|
* section under a non-native mode; a runtime whose language is not a key
|
|
12473
12820
|
* fails the assembly loudly (same idiom as `toolOrder` violations). Adding a
|
|
12474
|
-
* new backend language is three parallel edits — a {@link
|
|
12821
|
+
* new backend language is three parallel edits — a {@link PtcSdkLanguage}
|
|
12475
12822
|
* member, an entry here, and a `RUN_CODE_FLAVORS` entry in `ptc.ts` for
|
|
12476
12823
|
* its `run_code` schema strings — plus the renderer function this table points
|
|
12477
12824
|
* at. The `satisfies` clause pins this table's key set to that union, which
|
|
12478
12825
|
* the flavor table is checked against too, so any of the three left out is a
|
|
12479
12826
|
* typecheck failure. What no check reaches is the prose that names the values
|
|
12480
|
-
* instead of deriving them: the seam's `dsh-
|
|
12481
|
-
* `
|
|
12827
|
+
* instead of deriving them: the seam's `dsh-ptc-runtime` README pair, its
|
|
12828
|
+
* `PtcRuntime.language` JSDoc, and `docs/subsystems/ptc-runtime.md`
|
|
12482
12829
|
* with its zh pair, plus this package's own README pair and the
|
|
12483
12830
|
* {@link Config.mode} JSDoc.
|
|
12484
12831
|
*/
|
|
@@ -12717,12 +13064,13 @@ var ToolRuntime = class extends Service {
|
|
|
12717
13064
|
return {
|
|
12718
13065
|
name: "tools:sdk",
|
|
12719
13066
|
order: this.ctx.systemPrompt.getSectionOrder("TOOLS_SDK"),
|
|
13067
|
+
interpolate: false,
|
|
12720
13068
|
text: (context) => {
|
|
12721
13069
|
const mode = this.modeFor(context.scope);
|
|
12722
13070
|
if (mode === "native") return "";
|
|
12723
|
-
const runtime = this.
|
|
13071
|
+
const runtime = this.requirePtcRuntime(mode);
|
|
12724
13072
|
const render = SDK_RENDERERS[runtime.language];
|
|
12725
|
-
/* v8 ignore next --
|
|
13073
|
+
/* v8 ignore next -- requirePtcRuntime rejects an unknown language before this runs. */
|
|
12726
13074
|
if (render === void 0) throw new Error(`dsh-tools: no SDK renderer for ${runtime.language}`);
|
|
12727
13075
|
return render(this.sdkSchemas(context.scope));
|
|
12728
13076
|
}
|
|
@@ -12751,10 +13099,16 @@ var ToolRuntime = class extends Service {
|
|
|
12751
13099
|
* and only for scopes whose mode actually presents it.
|
|
12752
13100
|
* @returns the shared transport definition.
|
|
12753
13101
|
*/
|
|
12754
|
-
|
|
13102
|
+
requirePtcTransport() {
|
|
12755
13103
|
this.ptcTransport ??= createRunCodeTool(this, {
|
|
12756
|
-
requireRuntime: () => this.
|
|
12757
|
-
|
|
13104
|
+
requireRuntime: () => this.requirePtcRuntime(this.defaultMode),
|
|
13105
|
+
peekApprover: () => this.ctx.get("approval"),
|
|
13106
|
+
resolveSandboxPolicy: (exec) => {
|
|
13107
|
+
const policy = this.ctx.get("sandboxPolicy");
|
|
13108
|
+
if (policy === void 0) throw new Error("dsh-tools: confined PTC runtime requires sandboxPolicy");
|
|
13109
|
+
return policy.resolve(exec.agent === void 0 ? {} : { session: exec.agent.session });
|
|
13110
|
+
},
|
|
13111
|
+
peekRuntime: () => this.ctx.get("ptcRuntime"),
|
|
12758
13112
|
maxParallel: this.maxParallelSubCalls,
|
|
12759
13113
|
shapeDispatchLog: (dispatch) => this.shapeDispatchLog(dispatch)
|
|
12760
13114
|
});
|
|
@@ -12799,7 +13153,7 @@ var ToolRuntime = class extends Service {
|
|
|
12799
13153
|
schemas: [...view.visible.values()].map((definition) => this.schemaOf(definition, false)),
|
|
12800
13154
|
knownNames: [...view.knownNames]
|
|
12801
13155
|
};
|
|
12802
|
-
this.
|
|
13156
|
+
this.requirePtcRuntime(mode);
|
|
12803
13157
|
const schemas = [...view.visible.values()].map((definition) => this.schemaOf(definition, false));
|
|
12804
13158
|
if (mode === "ptc") return {
|
|
12805
13159
|
schemas: schemas.filter((schema) => schema.name === RUN_CODE_NAME),
|
|
@@ -12811,10 +13165,10 @@ var ToolRuntime = class extends Service {
|
|
|
12811
13165
|
};
|
|
12812
13166
|
}
|
|
12813
13167
|
/**
|
|
12814
|
-
* Resolve the
|
|
13168
|
+
* Resolve the PTC runtime or throw the actionable misconfiguration error.
|
|
12815
13169
|
* Read at use time (assembly / run_code execution), NOT via static
|
|
12816
13170
|
* `inject`: an inject entry would hold `ctx.tools` — and every tool plugin
|
|
12817
|
-
* behind it — hostage to a
|
|
13171
|
+
* behind it — hostage to a PTC runtime existing even under `mode:
|
|
12818
13172
|
* 'native'`.
|
|
12819
13173
|
*
|
|
12820
13174
|
* Assembly and `run_code` execution read separately, so the language is not
|
|
@@ -12822,12 +13176,11 @@ var ToolRuntime = class extends Service {
|
|
|
12822
13176
|
* reads return the same flavor — but a reload that swapped in a second
|
|
12823
13177
|
* language between them would hand a program written against one SDK to the
|
|
12824
13178
|
* other. Binding it is deferred until a second backend ships (the first
|
|
12825
|
-
* point it is testable)
|
|
12826
|
-
* [language-dispatch note](../../../../.agents/notes/implemented/feature/2026-07-31-ptc-language-dispatch.md).
|
|
13179
|
+
* point it is testable).
|
|
12827
13180
|
*/
|
|
12828
|
-
|
|
12829
|
-
const runtime = this.ctx.get("
|
|
12830
|
-
if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a
|
|
13181
|
+
requirePtcRuntime(mode) {
|
|
13182
|
+
const runtime = this.ctx.get("ptcRuntime");
|
|
13183
|
+
if (!runtime) throw new Error(`dsh-tools: mode "${mode}" requires a PTC runtime — load a ctx.ptcRuntime implementation (e.g. @deepseek-ai/dsh-ptc-runtime-node) or set tools mode to "native"`);
|
|
12831
13184
|
if (!Object.hasOwn(SDK_RENDERERS, runtime.language)) {
|
|
12832
13185
|
const known = Object.keys(SDK_RENDERERS).map((name) => JSON.stringify(name)).join(", ");
|
|
12833
13186
|
throw new Error(`dsh-tools: no SDK renderer registered for runtime language ${JSON.stringify(runtime.language)} (known: ${known})`);
|
|
@@ -12909,9 +13262,9 @@ var ToolRuntime = class extends Service {
|
|
|
12909
13262
|
* A restriction filters what a scope inherits — the global layer and every
|
|
12910
13263
|
* ancestor layer on its chain — and never what its OWN layer registers.
|
|
12911
13264
|
* That exemption is what a per-child capability filter has to keep intact:
|
|
12912
|
-
* the delegation runtime registers a child's
|
|
12913
|
-
*
|
|
12914
|
-
*
|
|
13265
|
+
* the delegation runtime registers a child's structured-output tool into the
|
|
13266
|
+
* child's own layer, and a filter naming the capabilities the child may use
|
|
13267
|
+
* must not strip the machinery it answers through.
|
|
12915
13268
|
*
|
|
12916
13269
|
* Reading the exempt set as "the global layer" instead of "not mine" held
|
|
12917
13270
|
* only while every model-facing tool sat in the host composition. Once
|
|
@@ -12941,7 +13294,7 @@ var ToolRuntime = class extends Service {
|
|
|
12941
13294
|
knownNames.add(name);
|
|
12942
13295
|
visible.set(name, definition);
|
|
12943
13296
|
}
|
|
12944
|
-
if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.
|
|
13297
|
+
if (this.modeFor(scope) !== "native") visible.set(RUN_CODE_NAME, this.requirePtcTransport());
|
|
12945
13298
|
return {
|
|
12946
13299
|
visible,
|
|
12947
13300
|
knownNames,
|
|
@@ -13029,7 +13382,7 @@ var ToolRuntime = class extends Service {
|
|
|
13029
13382
|
}
|
|
13030
13383
|
/**
|
|
13031
13384
|
* Run the `tools/ptc-dispatch-log` waterfall over one settled sub-dispatch
|
|
13032
|
-
* and return the content the bridge should log on `tool/
|
|
13385
|
+
* and return the content the bridge should log on `tool/ptc-dispatch`.
|
|
13033
13386
|
* Contained: when a listener throws, the method logs the original settled
|
|
13034
13387
|
* content; that failure must not fail the dispatch or omit the settle event. Private:
|
|
13035
13388
|
* the ONE consumer is the `run_code` bridge this registry constructs, which
|
|
@@ -13112,6 +13465,7 @@ var ToolRuntime = class extends Service {
|
|
|
13112
13465
|
signal,
|
|
13113
13466
|
...agent !== void 0 ? { agent } : {},
|
|
13114
13467
|
...parent !== void 0 ? { parent } : {},
|
|
13468
|
+
...exec.schema !== void 0 ? { schema: exec.schema } : {},
|
|
13115
13469
|
deferContext(context) {
|
|
13116
13470
|
deferredContexts.push(context);
|
|
13117
13471
|
},
|
|
@@ -13194,7 +13548,13 @@ var ToolRuntime = class extends Service {
|
|
|
13194
13548
|
exec,
|
|
13195
13549
|
result: toolAbortedBeforeDispatchResult()
|
|
13196
13550
|
});
|
|
13551
|
+
if (decision.kind === "cancel") return await next({
|
|
13552
|
+
kind: "post-result",
|
|
13553
|
+
exec,
|
|
13554
|
+
result: toolAbortedBeforeDispatchResult()
|
|
13555
|
+
});
|
|
13197
13556
|
const denialReason = decision.kind === "allow" ? this.guardReason(exec) : decision.reason;
|
|
13557
|
+
const denialInfo = decision.kind === "deny" ? decision.info : void 0;
|
|
13198
13558
|
if (denialReason !== void 0) return await next({
|
|
13199
13559
|
kind: "post-result",
|
|
13200
13560
|
exec,
|
|
@@ -13204,7 +13564,10 @@ var ToolRuntime = class extends Service {
|
|
|
13204
13564
|
text: `Error: ${denialReason}`
|
|
13205
13565
|
}],
|
|
13206
13566
|
isError: true,
|
|
13207
|
-
error: {
|
|
13567
|
+
error: {
|
|
13568
|
+
message: denialReason,
|
|
13569
|
+
...denialInfo === void 0 ? {} : { info: denialInfo }
|
|
13570
|
+
}
|
|
13208
13571
|
})
|
|
13209
13572
|
});
|
|
13210
13573
|
if (this.callerCancelled(exec)) return await next({
|
|
@@ -13655,11 +14018,33 @@ function toolAbortedBeforeDispatchResult(prior) {
|
|
|
13655
14018
|
};
|
|
13656
14019
|
}
|
|
13657
14020
|
//#endregion
|
|
13658
|
-
//#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.
|
|
14021
|
+
//#region node_modules/.pnpm/@deepseek-ai+dsh-agent@0.1.6-alpha.1_ce40d13c69e7e1ce48818baba37665e1/node_modules/@deepseek-ai/dsh-agent/lib/index.js
|
|
13659
14022
|
/**
|
|
13660
14023
|
* Agent-scoped model selection shared by runtime entry points.
|
|
13661
14024
|
* @module @deepseek-ai/dsh-agent/model-selection
|
|
13662
14025
|
*/
|
|
14026
|
+
function sameRoute(left, right) {
|
|
14027
|
+
return left.provider === right.provider && left.model === right.model;
|
|
14028
|
+
}
|
|
14029
|
+
function routeLabel(route, other) {
|
|
14030
|
+
return route.provider === other.provider ? route.model : `${route.provider}/${route.model}`;
|
|
14031
|
+
}
|
|
14032
|
+
function modelSwitchNotice(previous, selected) {
|
|
14033
|
+
const from = routeLabel(previous, selected);
|
|
14034
|
+
const to = routeLabel(selected, previous);
|
|
14035
|
+
return createUserMessage({
|
|
14036
|
+
content: [{
|
|
14037
|
+
type: "text",
|
|
14038
|
+
text: `[model changed: assistant turns above this point were generated by ${from}; the session continues with ${to}]`
|
|
14039
|
+
}],
|
|
14040
|
+
source: {
|
|
14041
|
+
kind: "plugin",
|
|
14042
|
+
plugin: "model-selection",
|
|
14043
|
+
form: "notice",
|
|
14044
|
+
summary: boundContextSummary(`${from} → ${to}`)
|
|
14045
|
+
}
|
|
14046
|
+
});
|
|
14047
|
+
}
|
|
13663
14048
|
/**
|
|
13664
14049
|
* Couple one mutable selection to Agent-scoped prompt assembly and request routing.
|
|
13665
14050
|
* Prompt assembly snapshots the selected model before delegating, then applies
|
|
@@ -13668,9 +14053,15 @@ function toolAbortedBeforeDispatchResult(prior) {
|
|
|
13668
14053
|
* surfaces. An absent selected effort clears any inherited effort, restoring
|
|
13669
14054
|
* the selected model's provider/default behavior.
|
|
13670
14055
|
*
|
|
14056
|
+
* A provider/model change appends a durable user-role notice to the next
|
|
14057
|
+
* admitted request. It compares the assembled selection with the latest
|
|
14058
|
+
* request header; effort-only changes and empty no-request decisions add no
|
|
14059
|
+
* notice. Failure before header persistence repeats the notice on the next
|
|
14060
|
+
* request.
|
|
14061
|
+
*
|
|
13671
14062
|
* @param agentCtx - The selected Agent's scoped context.
|
|
13672
14063
|
* @param selection - Mutable selection owned by the calling entry point.
|
|
13673
|
-
* @returns Disposer for
|
|
14064
|
+
* @returns Disposer for all scoped waterfall listeners.
|
|
13674
14065
|
*/
|
|
13675
14066
|
function installModelSelection(agentCtx, selection) {
|
|
13676
14067
|
const disposeAssembly = agentCtx.on("system-prompt/assemble", async (_assembly, _context, next) => {
|
|
@@ -13699,9 +14090,22 @@ function installModelSelection(agentCtx, selection) {
|
|
|
13699
14090
|
...selected.reasoningEffort === void 0 ? {} : { reasoningEffort: selected.reasoningEffort }
|
|
13700
14091
|
};
|
|
13701
14092
|
});
|
|
14093
|
+
const disposeNotice = agentCtx.on("agent/pre-step", async ({ agent, messages, signal, step }, next) => {
|
|
14094
|
+
const decision = await next();
|
|
14095
|
+
if (decision.kind === "reject" || signal.aborted) return decision;
|
|
14096
|
+
if (decision.messages.length === 0 && (step === 1 || messages.length > 0)) return decision;
|
|
14097
|
+
const selected = selection.assembled;
|
|
14098
|
+
const previous = agent.session.requestHeader()?.config;
|
|
14099
|
+
if (selected === void 0 || previous === void 0 || sameRoute(selected, previous)) return decision;
|
|
14100
|
+
return {
|
|
14101
|
+
...decision,
|
|
14102
|
+
messages: [...decision.messages, modelSwitchNotice(previous, selected)]
|
|
14103
|
+
};
|
|
14104
|
+
}, { prepend: true });
|
|
13702
14105
|
return () => {
|
|
13703
14106
|
disposeAssembly();
|
|
13704
14107
|
disposeRequest();
|
|
14108
|
+
disposeNotice();
|
|
13705
14109
|
};
|
|
13706
14110
|
}
|
|
13707
14111
|
//#endregion
|
|
@@ -13853,8 +14257,10 @@ function registerCreate(env) {
|
|
|
13853
14257
|
...model !== "" ? { model } : {},
|
|
13854
14258
|
...reasoningEffort === void 0 ? {} : { reasoningEffort }
|
|
13855
14259
|
},
|
|
13856
|
-
setup: (agentCtx) => {
|
|
13857
|
-
|
|
14260
|
+
setup: async (agentCtx) => {
|
|
14261
|
+
const requestedPreset = typeof args.agentPreset === "string" && args.agentPreset.trim() !== "" ? args.agentPreset.trim() : void 0;
|
|
14262
|
+
if (requestedPreset !== void 0) await env.ctx.agentPresets.mount(agentCtx, requestedPreset);
|
|
14263
|
+
else if (caller !== void 0) env.ctx.agentPresets.composeFrom(agentCtx, caller.ctx);
|
|
13858
14264
|
if (installModelSelection$1 !== void 0) {
|
|
13859
14265
|
installModelSelection$1(agentCtx, selection);
|
|
13860
14266
|
return;
|
|
@@ -14022,7 +14428,11 @@ function registerResume(env) {
|
|
|
14022
14428
|
}
|
|
14023
14429
|
let headers = [];
|
|
14024
14430
|
try {
|
|
14025
|
-
headers = await env.ctx.sessionPersistence.list()
|
|
14431
|
+
headers = (await env.ctx.sessionPersistence.list()).map((rec) => ({
|
|
14432
|
+
id: rec.header.id,
|
|
14433
|
+
...rec.header.cwd === void 0 ? {} : { cwd: rec.header.cwd },
|
|
14434
|
+
createdAt: rec.header.createdAt
|
|
14435
|
+
}));
|
|
14026
14436
|
} catch (error) {
|
|
14027
14437
|
throw new Error("session persistence unavailable: " + (error instanceof Error ? error.message : String(error)));
|
|
14028
14438
|
}
|
|
@@ -14185,7 +14595,7 @@ function registerSegments(env) {
|
|
|
14185
14595
|
events = sessionEvents(agent.session);
|
|
14186
14596
|
live = true;
|
|
14187
14597
|
} else try {
|
|
14188
|
-
events = (await env.ctx
|
|
14598
|
+
events = (await inspectPersistedSession(env.ctx, args.sessionId)).events;
|
|
14189
14599
|
live = false;
|
|
14190
14600
|
} catch (error) {
|
|
14191
14601
|
throw new Error(String(error));
|
|
@@ -14279,7 +14689,7 @@ function registerRead(env) {
|
|
|
14279
14689
|
} else {
|
|
14280
14690
|
let inspection;
|
|
14281
14691
|
try {
|
|
14282
|
-
inspection = await env.ctx
|
|
14692
|
+
inspection = await inspectPersistedSession(env.ctx, args.sessionId);
|
|
14283
14693
|
} catch (error) {
|
|
14284
14694
|
throw new Error("cannot read session " + JSON.stringify(args.sessionId) + ": " + (error instanceof Error ? error.message : String(error)));
|
|
14285
14695
|
}
|
|
@@ -14403,7 +14813,8 @@ function registerFind(env) {
|
|
|
14403
14813
|
}
|
|
14404
14814
|
if (args.liveOnly !== true) try {
|
|
14405
14815
|
const persistence = env.ctx.sessionPersistence;
|
|
14406
|
-
for (const
|
|
14816
|
+
for (const rec of await persistence.list()) {
|
|
14817
|
+
const header = rec.header;
|
|
14407
14818
|
if (items.some((item) => item.sessionId === header.id)) continue;
|
|
14408
14819
|
items.push({
|
|
14409
14820
|
sessionId: header.id,
|
|
@@ -14439,13 +14850,12 @@ function registerFind(env) {
|
|
|
14439
14850
|
const wsFilter = typeof args.workspaceId === "string" ? args.workspaceId.trim() : "";
|
|
14440
14851
|
const cwdFilter = typeof args.cwd === "string" ? args.cwd.trim().toLowerCase() : "";
|
|
14441
14852
|
if (titleFilter !== "" || query !== "" && items.some((item) => !item.live)) {
|
|
14442
|
-
const persistence = env.ctx.sessionPersistence;
|
|
14443
14853
|
let inspected = 0;
|
|
14444
14854
|
for (const item of items) {
|
|
14445
14855
|
if (inspected >= 30) break;
|
|
14446
14856
|
if (item.live || item.title !== void 0) continue;
|
|
14447
14857
|
try {
|
|
14448
|
-
item.title = titleOf((await
|
|
14858
|
+
item.title = titleOf((await inspectPersistedSession(env.ctx, item.sessionId)).events);
|
|
14449
14859
|
inspected += 1;
|
|
14450
14860
|
} catch {
|
|
14451
14861
|
inspected += 1;
|
|
@@ -14950,7 +15360,6 @@ function registerArchive(env) {
|
|
|
14950
15360
|
async execute(args) {
|
|
14951
15361
|
const items = env.ctx.workspaceRegistry.archivedSessionIds.map(String).map((id) => ({ sessionId: id }));
|
|
14952
15362
|
if (args.resolveTitles === true && items.length > 0) {
|
|
14953
|
-
const persistence = env.ctx.sessionPersistence;
|
|
14954
15363
|
const registryTitles = /* @__PURE__ */ new Map();
|
|
14955
15364
|
try {
|
|
14956
15365
|
const records = await env.registry.all();
|
|
@@ -14962,7 +15371,7 @@ function registerArchive(env) {
|
|
|
14962
15371
|
continue;
|
|
14963
15372
|
}
|
|
14964
15373
|
try {
|
|
14965
|
-
item.title = titleOf((await
|
|
15374
|
+
item.title = titleOf((await inspectPersistedSession(env.ctx, item.sessionId)).events);
|
|
14966
15375
|
} catch {}
|
|
14967
15376
|
}
|
|
14968
15377
|
}
|