@code-yeongyu/senpi 2026.10.24-2 → 2026.10.24-4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/dist/bundle/chunks/{args-6T5EQVY3.js → args-JXULI4EH.js} +1 -1
- package/dist/bundle/chunks/{chunk-VUKNGMDT.js → chunk-3LNSLJ7N.js} +1 -1
- package/dist/bundle/chunks/chunk-3VOG6WFU.js +27 -0
- package/dist/bundle/chunks/{chunk-HHYSXDYP.js → chunk-42OY5SZZ.js} +2 -2
- package/dist/bundle/chunks/chunk-7IRLFYNM.js +23 -0
- package/dist/bundle/chunks/{chunk-FIBIVBQK.js → chunk-7UUOGZKR.js} +1 -1
- package/dist/bundle/chunks/chunk-BMYNMUVZ.js +7 -0
- package/dist/bundle/chunks/{chunk-JAXZOEJE.js → chunk-BWA4FVFW.js} +1 -1
- package/dist/bundle/chunks/{chunk-AGQSRWNN.js → chunk-EHQXLHRB.js} +1 -1
- package/dist/bundle/chunks/chunk-EWOEVVQT.js +4 -0
- package/dist/bundle/chunks/{chunk-YJA2B7FQ.js → chunk-FDL4CF6F.js} +1 -1
- package/dist/bundle/chunks/{chunk-RQHK4QZ5.js → chunk-FWXMMMCV.js} +1 -1
- package/dist/bundle/chunks/{chunk-OA5INWHI.js → chunk-GVJ76VQI.js} +102 -42
- package/dist/bundle/chunks/{chunk-HCF5M6NA.js → chunk-GXY5JEI5.js} +1 -1
- package/dist/bundle/chunks/{chunk-VZAYN5SB.js → chunk-HKUXKTFW.js} +1 -1
- package/dist/bundle/chunks/chunk-II22E3CV.js +3 -0
- package/dist/bundle/chunks/{chunk-ONLNXGO3.js → chunk-IUHU5PEC.js} +1 -1
- package/dist/bundle/chunks/{chunk-LR6Z6V54.js → chunk-NQC7MI2G.js} +1 -1
- package/dist/bundle/chunks/{chunk-IELM5U6I.js → chunk-PXKF2RHD.js} +2 -2
- package/dist/bundle/chunks/{chunk-BRXN5R2F.js → chunk-QH2HSCMX.js} +1 -1
- package/dist/bundle/chunks/{chunk-QQSCUEYJ.js → chunk-RHHBXIRN.js} +2 -5
- package/dist/bundle/chunks/chunk-RVYSJBZ7.js +7 -0
- package/dist/bundle/chunks/chunk-SGDOZT6B.js +8 -0
- package/dist/bundle/chunks/{chunk-BZ75DRZB.js → chunk-U67ML6CQ.js} +4 -2
- package/dist/bundle/chunks/{chunk-3N2PQEQV.js → chunk-UT6AJHPK.js} +1 -1
- package/dist/bundle/chunks/{chunk-RAIZG6HA.js → chunk-V3CK2AVC.js} +1 -1
- package/dist/bundle/chunks/{chunk-CZR7C6CY.js → chunk-VOBD6FQG.js} +1 -1
- package/dist/bundle/chunks/{chunk-HRPMLI7O.js → chunk-VRDU425E.js} +2 -2
- package/dist/bundle/chunks/{chunk-OUPD5LWY.js → chunk-XUFUKDKJ.js} +3 -3
- package/dist/bundle/chunks/{chunk-SGATKHO4.js → chunk-Y5OTHMXO.js} +1 -1
- package/dist/bundle/chunks/{chunk-QEQG42HL.js → chunk-ZGAB7WQA.js} +1 -1
- package/dist/bundle/chunks/cli-main-UH3MAREK.js +3 -0
- package/dist/bundle/chunks/{dispatch-KQEGIXQW.js → dispatch-DEP4PEDZ.js} +3 -2
- package/dist/bundle/chunks/{help-fast-path-6PVN7WI5.js → help-fast-path-ZHZGXAUG.js} +1 -1
- package/dist/bundle/chunks/host-command-OQR4RDTM.js +2 -0
- package/dist/bundle/chunks/host-lifecycle-U36U7JTE.js +3 -0
- package/dist/bundle/chunks/host-lifecycle.js +26 -21
- package/dist/bundle/chunks/host-session-command-IGB27ZPJ.js +20 -0
- package/dist/bundle/chunks/{host-socket-request-KKGH3JHV.js → host-socket-request-ZDJGSSZO.js} +1 -1
- package/dist/bundle/chunks/interactive-mode-R5RCSJ2F.js +2 -0
- package/dist/bundle/chunks/{list-tips-BO5RP34W.js → list-tips-CREX4IXZ.js} +1 -1
- package/dist/bundle/chunks/{multi-session-host-O5GZQSRL.js → multi-session-host-YZEMYUFY.js} +12 -12
- package/dist/bundle/chunks/{package-manager-cli-LC5GAGTW.js → package-manager-cli-5FOXDKUA.js} +1 -1
- package/dist/bundle/chunks/{role-4G43UDOC.js → role-M2MTVACJ.js} +1 -1
- package/dist/bundle/chunks/{rotation-stream-RXMCJJUL.js → rotation-stream-U7YQMC7H.js} +1 -1
- package/dist/bundle/chunks/rpc-mode-6K62CZBW.js +2 -0
- package/dist/bundle/chunks/rpc-monitor-source-OL5KU6NO.js +3 -0
- package/dist/bundle/chunks/{schedule-command-QNCVE4HM.js → schedule-command-XBW4EOG5.js} +1 -1
- package/dist/bundle/chunks/session-control-endpoint-54TMCS7Q.js +3 -0
- package/dist/bundle/chunks/{session-picker-HIC5ZTE6.js → session-picker-P2VUU2MQ.js} +1 -1
- package/dist/bundle/chunks/session-worker.js +437 -368
- package/dist/bundle/cli.js +2 -2
- package/dist/bundle/host-supervisor.js +26 -21
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/bundle/runtime-manifest.json +1 -1
- package/dist/cli/args.d.ts +2 -0
- package/dist/cli/args.js +27 -0
- package/dist/cli/host-command-args.d.ts +33 -0
- package/dist/cli/host-command-args.js +145 -0
- package/dist/cli/host-command.d.ts +1 -30
- package/dist/cli/host-command.js +5 -137
- package/dist/cli/host-session-command.d.ts +1 -0
- package/dist/cli/host-session-command.js +5 -3
- package/dist/core/agent-session.js +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/index.js +4 -2
- package/dist/core/extensions/builtin/anthropic-subscription/options.js +2 -1
- package/dist/core/extensions/builtin/anthropic-subscription/sdk-boundary.js +9 -2
- package/dist/core/extensions/builtin/anthropic-subscription/session-cwd.d.ts +3 -0
- package/dist/core/extensions/builtin/anthropic-subscription/session-cwd.js +9 -0
- package/dist/core/extensions/builtin/anthropic-subscription/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/anthropic-subscription/settings.js +3 -1
- package/dist/core/extensions/builtin/anthropic-subscription/stream.js +4 -1
- package/dist/core/extensions/builtin/btw/index.js +4 -1
- package/dist/core/extensions/builtin/compaction/lane-policy.js +3 -1
- package/dist/core/extensions/builtin/look-at/runner.js +1 -0
- package/dist/core/extensions/builtin/mcp/connection-types.d.ts +2 -0
- package/dist/core/extensions/builtin/mcp/connection.js +3 -0
- package/dist/core/extensions/builtin/mcp/elicitation.d.ts +5 -2
- package/dist/core/extensions/builtin/mcp/elicitation.js +57 -11
- package/dist/core/extensions/builtin/mcp/index.js +1 -1
- package/dist/core/extensions/builtin/mcp/modern/dispatch.js +6 -9
- package/dist/core/extensions/builtin/mcp/service-connection.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/service-connection.js +1 -0
- package/dist/core/extensions/builtin/mcp/service.js +1 -0
- package/dist/core/extensions/builtin/mcp/transport-sdk.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/transport-sdk.js +5 -5
- package/dist/core/extensions/builtin/mcp/transport.d.ts +1 -0
- package/dist/core/extensions/builtin/mcp/transport.js +1 -0
- package/dist/core/extensions/builtin/prompt-preset/contract.js +6 -1
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3-1.d.ts +3 -0
- package/dist/core/extensions/builtin/prompt-preset/kimi-k3-1.js +93 -0
- package/dist/core/extensions/builtin/prompt-preset/matchers.d.ts +2 -0
- package/dist/core/extensions/builtin/prompt-preset/matchers.js +9 -0
- package/dist/core/extensions/builtin/prompt-preset/presets.js +3 -0
- package/dist/core/extensions/builtin/prompt-preset/settings.d.ts +1 -1
- package/dist/core/extensions/builtin/prompt-preset/settings.js +1 -0
- package/dist/core/extensions/builtin/terminal/rpc-monitor-observer.d.ts +2 -1
- package/dist/core/extensions/builtin/terminal/rpc-monitor-observer.js +12 -4
- package/dist/core/external-admission.d.ts +4 -1
- package/dist/core/external-admission.js +18 -2
- package/dist/core/lifecycle-session-binding.js +20 -0
- package/dist/core/sdk.js +1 -0
- package/dist/core/session-spawned-by.d.ts +4 -0
- package/dist/core/session-spawned-by.js +16 -0
- package/dist/main.js +7 -2
- package/dist/modes/rpc/host-admission-proxy.d.ts +2 -1
- package/dist/modes/rpc/host-admission-proxy.js +10 -9
- package/dist/modes/rpc/host-cli-entry.d.ts +2 -0
- package/dist/modes/rpc/host-cli-entry.js +13 -1
- package/dist/modes/rpc/host-ensure-client.d.ts +5 -1
- package/dist/modes/rpc/host-ensure-client.js +8 -0
- package/dist/modes/rpc/host-ensure-types.d.ts +1 -0
- package/dist/modes/rpc/host-ensure.js +6 -11
- package/dist/modes/rpc/host-gc-pass.js +3 -0
- package/dist/modes/rpc/host-gc.js +3 -0
- package/dist/modes/rpc/host-internal-transport.d.ts +16 -5
- package/dist/modes/rpc/host-internal-transport.js +40 -9
- package/dist/modes/rpc/host-lifecycle-proxy.d.ts +4 -8
- package/dist/modes/rpc/host-lifecycle-proxy.js +9 -21
- package/dist/modes/rpc/host-lifecycle-shutdown.d.ts +2 -0
- package/dist/modes/rpc/host-lifecycle-shutdown.js +3 -0
- package/dist/modes/rpc/host-lifecycle.js +9 -16
- package/dist/modes/rpc/host-observe-request.js +1 -1
- package/dist/modes/rpc/host-probe.d.ts +8 -6
- package/dist/modes/rpc/host-probe.js +13 -13
- package/dist/modes/rpc/host-request-key-root.d.ts +8 -0
- package/dist/modes/rpc/host-request-key-root.js +14 -0
- package/dist/modes/rpc/host-runner.d.ts +3 -1
- package/dist/modes/rpc/host-runner.js +6 -1
- package/dist/modes/rpc/host-socket-bind.d.ts +6 -0
- package/dist/modes/rpc/host-socket-bind.js +42 -0
- package/dist/modes/rpc/host-socket-request.d.ts +3 -2
- package/dist/modes/rpc/host-socket-request.js +55 -10
- package/dist/modes/rpc/host-status.d.ts +3 -2
- package/dist/modes/rpc/host-status.js +5 -0
- package/dist/modes/rpc/host-supervisor-log.d.ts +1 -0
- package/dist/modes/rpc/host-supervisor-log.js +3 -0
- package/dist/modes/rpc/host-watchdog.d.ts +8 -1
- package/dist/modes/rpc/host-watchdog.js +37 -12
- package/dist/modes/rpc/internal-channel.js +14 -14
- package/dist/modes/rpc/multi-session-host.js +18 -46
- package/dist/modes/rpc/rpc-auth-client.d.ts +13 -0
- package/dist/modes/rpc/rpc-auth-client.js +142 -0
- package/dist/modes/rpc/rpc-auth-proof.d.ts +12 -0
- package/dist/modes/rpc/rpc-auth-proof.js +27 -0
- package/dist/modes/rpc/rpc-client-socket.d.ts +5 -0
- package/dist/modes/rpc/rpc-client-socket.js +30 -0
- package/dist/modes/rpc/rpc-client.d.ts +2 -0
- package/dist/modes/rpc/rpc-client.js +2 -24
- package/dist/modes/rpc/rpc-host-command-types.d.ts +4 -0
- package/dist/modes/rpc/rpc-protocol-info-types.d.ts +6 -0
- package/dist/modes/rpc/rpc-public-auth.d.ts +41 -0
- package/dist/modes/rpc/rpc-public-auth.js +237 -0
- package/dist/modes/rpc/rpc-public-key.d.ts +28 -0
- package/dist/modes/rpc/rpc-public-key.js +193 -0
- package/dist/modes/rpc/session-router-open-profile.js +2 -10
- package/dist/modes/rpc/socket-ownership.d.ts +7 -0
- package/dist/modes/rpc/socket-ownership.js +17 -0
- package/docs/rpc.md +108 -2
- package/docs/settings.md +1 -1
- package/docs/usage.md +14 -0
- package/package.json +6 -6
- package/dist/bundle/chunks/chunk-3474DPZK.js +0 -2
- package/dist/bundle/chunks/chunk-64CFJHKT.js +0 -7
- package/dist/bundle/chunks/chunk-B6NJHBLH.js +0 -21
- package/dist/bundle/chunks/chunk-HZTQHE5O.js +0 -26
- package/dist/bundle/chunks/chunk-IBDADH5Z.js +0 -4
- package/dist/bundle/chunks/chunk-OJZD7CO7.js +0 -8
- package/dist/bundle/chunks/cli-main-4JNPG6LB.js +0 -3
- package/dist/bundle/chunks/host-command-I3ZMWQQ3.js +0 -2
- package/dist/bundle/chunks/host-lifecycle-QEO422VW.js +0 -3
- package/dist/bundle/chunks/host-session-command-INULKX6E.js +0 -20
- package/dist/bundle/chunks/interactive-mode-SYWJVPKK.js +0 -2
- package/dist/bundle/chunks/rpc-mode-JMCYSP4P.js +0 -2
- package/dist/bundle/chunks/rpc-monitor-source-34AQDTZ6.js +0 -3
- package/dist/bundle/chunks/session-control-endpoint-IW5X56WN.js +0 -3
|
@@ -4,6 +4,7 @@ import { CONFIG_DIR_NAME, getAgentDir } from "../../../../config.js";
|
|
|
4
4
|
import { PROJECT_RULES_END_MARKER, PROJECT_RULES_HEADING, PROJECT_RULES_REGION_END_MARKER, PROJECT_RULES_REGION_START_MARKER, PROJECT_RULES_START_MARKER, } from "../rules/rules/constants.js";
|
|
5
5
|
import { plannedContextWindow, sdkModelId } from "./context-window.js";
|
|
6
6
|
import { presetAppendDeprecationGuidance } from "./guidance.js";
|
|
7
|
+
import { requireAnthropicSubscriptionCwd } from "./session-cwd.js";
|
|
7
8
|
import { loadAnthropicSubscriptionProviderSettingsFromDisk, resolveCompactionOwner, resolveSystemPromptMode, } from "./settings.js";
|
|
8
9
|
import { loadOverrideSystemPrompt, resolveCustomSystemPrompt } from "./system-prompt.js";
|
|
9
10
|
import { BUILTIN_SDK_TOOLS, canUseTool, HOST_TOOL_DENIAL_HOOKS } from "./tools.js";
|
|
@@ -178,7 +179,7 @@ function resolveSettingSources(providerSettings, mode, authLane) {
|
|
|
178
179
|
return ["user", "project"];
|
|
179
180
|
}
|
|
180
181
|
export function buildAnthropicSubscriptionQueryOptions(input) {
|
|
181
|
-
const cwd = input.cwd
|
|
182
|
+
const cwd = requireAnthropicSubscriptionCwd(input.cwd);
|
|
182
183
|
const providerSettings = input.providerSettings ?? loadAnthropicSubscriptionProviderSettingsFromDisk(cwd);
|
|
183
184
|
const appendSystemPrompt = providerSettings.appendSystemPrompt !== false;
|
|
184
185
|
const resolvedMode = resolveSystemPromptMode(providerSettings);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { loadClaudeAgentSdk, loadedClaudeAgentSdk } from "./sdk-boundary.lazy.js";
|
|
2
|
+
import { requireAnthropicSubscriptionCwd } from "./session-cwd.js";
|
|
2
3
|
export { loadClaudeAgentSdk } from "./sdk-boundary.lazy.js";
|
|
3
4
|
/**
|
|
4
5
|
* Reads the deferred SDK module for a synchronous boundary member.
|
|
@@ -18,9 +19,15 @@ function requireLoadedSdk(member) {
|
|
|
18
19
|
return sdk;
|
|
19
20
|
}
|
|
20
21
|
const defaultSdkBoundary = {
|
|
21
|
-
query: (input) =>
|
|
22
|
+
query: (input) => {
|
|
23
|
+
const cwd = requireAnthropicSubscriptionCwd(input.options?.cwd);
|
|
24
|
+
return requireLoadedSdk("query").query({ ...input, options: { ...input.options, cwd } });
|
|
25
|
+
},
|
|
22
26
|
createSdkMcpServer: (options) => requireLoadedSdk("createSdkMcpServer").createSdkMcpServer(options),
|
|
23
|
-
getSessionMessages: async (sessionId, options) =>
|
|
27
|
+
getSessionMessages: async (sessionId, options) => {
|
|
28
|
+
const dir = requireAnthropicSubscriptionCwd(options?.dir);
|
|
29
|
+
return (await loadClaudeAgentSdk()).getSessionMessages(sessionId, { ...options, dir });
|
|
30
|
+
},
|
|
24
31
|
};
|
|
25
32
|
let activeSdkBoundary = defaultSdkBoundary;
|
|
26
33
|
export function getSdkBoundary() {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { isAbsolute } from "node:path";
|
|
2
|
+
/** Every SDK query and lane-settings lookup must belong to an explicit session. */
|
|
3
|
+
export function requireAnthropicSubscriptionCwd(cwd) {
|
|
4
|
+
if (!cwd || !isAbsolute(cwd)) {
|
|
5
|
+
throw new Error("Anthropic Subscription requires an absolute session cwd; the host working directory is never used.");
|
|
6
|
+
}
|
|
7
|
+
return cwd;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=session-cwd.js.map
|
|
@@ -42,6 +42,6 @@ export declare function resolveSystemPromptMode(settings: AnthropicSubscriptionP
|
|
|
42
42
|
/** Load the provider block with env values taking precedence over project and global values. */
|
|
43
43
|
export declare function loadAnthropicSubscriptionProviderSettings(settingsManager: SettingsManager, environment?: Environment): AnthropicSubscriptionProviderSettings;
|
|
44
44
|
/** Load settings from Senpi's configured global and project settings.json paths. */
|
|
45
|
-
export declare function loadAnthropicSubscriptionProviderSettingsFromDisk(
|
|
45
|
+
export declare function loadAnthropicSubscriptionProviderSettingsFromDisk(sessionCwd: string): AnthropicSubscriptionProviderSettings;
|
|
46
46
|
export {};
|
|
47
47
|
//# sourceMappingURL=settings.d.ts.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { getAgentDir } from "../../../../config.js";
|
|
2
2
|
import { getFileContentRevision } from "../../../../utils/paths.js";
|
|
3
3
|
import { getSettingsPath, SettingsManager } from "../../../settings-manager.js";
|
|
4
|
+
import { requireAnthropicSubscriptionCwd } from "./session-cwd.js";
|
|
4
5
|
/** The one place the default lives: senpi owns compaction unless `compactionOwner: "sdk"` opts out. */
|
|
5
6
|
export function resolveCompactionOwner(settings) {
|
|
6
7
|
return settings.compactionOwner ?? "senpi";
|
|
@@ -152,7 +153,8 @@ function settingsFingerprint(path) {
|
|
|
152
153
|
}
|
|
153
154
|
let cachedAnthropicSubscriptionManager;
|
|
154
155
|
/** Load settings from Senpi's configured global and project settings.json paths. */
|
|
155
|
-
export function loadAnthropicSubscriptionProviderSettingsFromDisk(
|
|
156
|
+
export function loadAnthropicSubscriptionProviderSettingsFromDisk(sessionCwd) {
|
|
157
|
+
const cwd = requireAnthropicSubscriptionCwd(sessionCwd);
|
|
156
158
|
// fallbackEligible() calls this per candidate probe; cache the manager by
|
|
157
159
|
// (cwd, settings content revision) and re-apply env live to avoid locked disk reads.
|
|
158
160
|
const agentDir = getAgentDir();
|
|
@@ -13,6 +13,7 @@ import { refusalError } from "./refusal.js";
|
|
|
13
13
|
import { getSdkBoundary, loadClaudeAgentSdk } from "./sdk-boundary.js";
|
|
14
14
|
import { emitContinuityObservation } from "./session-observability.js";
|
|
15
15
|
import { forgetBinding } from "./session-reattach.js";
|
|
16
|
+
import { requireAnthropicSubscriptionCwd } from "./session-cwd.js";
|
|
16
17
|
import { residentSessionMessages } from "./session-stream.js";
|
|
17
18
|
import { loadAnthropicSubscriptionProviderSettingsFromDisk, resolveCompactionOwner, resumeModeSource, } from "./settings.js";
|
|
18
19
|
import { applyStreamEvent } from "./stream-events.js";
|
|
@@ -58,6 +59,7 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
58
59
|
let coldSeedEstimate;
|
|
59
60
|
let nativeCompactionStopped = false;
|
|
60
61
|
try {
|
|
62
|
+
const cwd = requireAnthropicSubscriptionCwd(options?.cwd);
|
|
61
63
|
// Resident before the synchronous SDK member below (getSdkBoundary().query)
|
|
62
64
|
// reads it - see sdk-boundary.lazy.ts.
|
|
63
65
|
await loadClaudeAgentSdk();
|
|
@@ -67,7 +69,7 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
67
69
|
if (sessionKey)
|
|
68
70
|
toolWatch.reconcileWithContext(sessionKey, context);
|
|
69
71
|
const toolWatchNote = toolWatch.buildPromptNote(sessionKey, context, resolvedTools.customToolNameToSdk);
|
|
70
|
-
const providerSettings = loadAnthropicSubscriptionProviderSettingsFromDisk(
|
|
72
|
+
const providerSettings = loadAnthropicSubscriptionProviderSettingsFromDisk(cwd);
|
|
71
73
|
const senpiOwnsCompaction = resolveCompactionOwner(providerSettings) === "senpi";
|
|
72
74
|
const toolLessRequest = options?.toolChoice === "none";
|
|
73
75
|
const mcpServers = toolLessRequest ? undefined : await buildCustomToolServers(resolvedTools.customTools);
|
|
@@ -79,6 +81,7 @@ export function streamAnthropicSubscription(model, context, options) {
|
|
|
79
81
|
model,
|
|
80
82
|
context,
|
|
81
83
|
streamOptions: options,
|
|
84
|
+
cwd,
|
|
82
85
|
providerSettings,
|
|
83
86
|
authLane,
|
|
84
87
|
tools: resolvedTools.sdkTools,
|
|
@@ -103,7 +103,10 @@ export default function btwExtension(pi) {
|
|
|
103
103
|
},
|
|
104
104
|
sessionId,
|
|
105
105
|
thinkingLevel: thinkingLevel === "off" ? undefined : thinkingLevel,
|
|
106
|
-
streamFn: (streamModel, streamContext, options) => ctx.modelRegistry.modelRuntime.streamSimple(streamModel, streamContext,
|
|
106
|
+
streamFn: (streamModel, streamContext, options) => ctx.modelRegistry.modelRuntime.streamSimple(streamModel, streamContext, {
|
|
107
|
+
...options,
|
|
108
|
+
cwd: ctx.cwd,
|
|
109
|
+
}),
|
|
107
110
|
}, context, {
|
|
108
111
|
signal: controller.signal,
|
|
109
112
|
onTextDelta: (delta) => {
|
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
*/
|
|
23
23
|
import { ANTHROPIC_SUBSCRIPTION_PROVIDER_ID } from "../anthropic-subscription/account-management.js";
|
|
24
24
|
import { isColdSeedOverflowMessage } from "../anthropic-subscription/cold-seed-budget.js";
|
|
25
|
+
import { requireAnthropicSubscriptionCwd } from "../anthropic-subscription/session-cwd.js";
|
|
25
26
|
import { loadAnthropicSubscriptionProviderSettingsFromDisk, resolveCompactionOwner, } from "../anthropic-subscription/settings.js";
|
|
26
27
|
/** Custom session entry type carrying a mirrored SDK compaction boundary. */
|
|
27
28
|
export const ANTHROPIC_SUBSCRIPTION_COMPACT_ENTRY_TYPE = "claude-sdk-oauth-compact";
|
|
@@ -76,8 +77,9 @@ export function createCompactionLanePolicy(options = {}) {
|
|
|
76
77
|
// undefined when the settings cannot be read, so callers fail closed to
|
|
77
78
|
// senpi's full behavior.
|
|
78
79
|
const readProviderSettings = (cwd) => {
|
|
80
|
+
const sessionCwd = requireAnthropicSubscriptionCwd(cwd);
|
|
79
81
|
try {
|
|
80
|
-
return load(
|
|
82
|
+
return load(sessionCwd);
|
|
81
83
|
}
|
|
82
84
|
catch {
|
|
83
85
|
return undefined;
|
|
@@ -33,6 +33,7 @@ export async function runLookAt(args, signal, ctx, store, dependencies = {}) {
|
|
|
33
33
|
((model, context, options) => ctx.modelRegistry.modelRuntime.streamSimple(model, context, options));
|
|
34
34
|
const reasoning = toStreamReasoning(resolved.thinkingLevel);
|
|
35
35
|
const response = await streamRunner(resolved.model, { systemPrompt: LOOK_AT_SYSTEM_PROMPT, messages: [userMessage] }, {
|
|
36
|
+
cwd: ctx.cwd,
|
|
36
37
|
...(reasoning === undefined ? {} : { reasoning }),
|
|
37
38
|
maxTokens: 4096,
|
|
38
39
|
signal: request.signal,
|
|
@@ -29,6 +29,8 @@ export interface ServerConnectionOptions {
|
|
|
29
29
|
readonly env?: Record<string, string | undefined>;
|
|
30
30
|
readonly authProvider?: McpOAuthProvider;
|
|
31
31
|
readonly elicitationUiProvider?: McpElicitationUiProvider;
|
|
32
|
+
/** Print/json processes cannot present elicitation; UI-less lessees fail independently. */
|
|
33
|
+
readonly elicitationEnabled?: boolean;
|
|
32
34
|
/** Present when the server declares references: every new transport re-reads them (senpi#3858). */
|
|
33
35
|
readonly resolveConfig?: () => Promise<McpServerConfig>;
|
|
34
36
|
/** Called when a shared renewal finds this owner's generation changed, so the owner re-keys. */
|
|
@@ -14,6 +14,7 @@ export class ServerConnection {
|
|
|
14
14
|
#config;
|
|
15
15
|
#authProvider;
|
|
16
16
|
#elicitationUiProvider;
|
|
17
|
+
#elicitationEnabled;
|
|
17
18
|
#resolveConfig;
|
|
18
19
|
#projectPolicy;
|
|
19
20
|
#policyAbort;
|
|
@@ -34,6 +35,7 @@ export class ServerConnection {
|
|
|
34
35
|
this.#env = options.env;
|
|
35
36
|
this.#authProvider = options.authProvider;
|
|
36
37
|
this.#elicitationUiProvider = options.elicitationUiProvider;
|
|
38
|
+
this.#elicitationEnabled = options.elicitationEnabled;
|
|
37
39
|
this.#resolveConfig = options.resolveConfig;
|
|
38
40
|
this.#projectPolicy = options.projectPolicy;
|
|
39
41
|
this.#startedGrantNames = options.projectPolicy?.initial.grantedNames ?? [];
|
|
@@ -239,6 +241,7 @@ export class ServerConnection {
|
|
|
239
241
|
return current;
|
|
240
242
|
},
|
|
241
243
|
elicitationUiProvider: this.#elicitationUiProvider,
|
|
244
|
+
elicitationEnabled: this.#elicitationEnabled,
|
|
242
245
|
logger: this.#logger,
|
|
243
246
|
resolveConfig: this.#resolveConfig,
|
|
244
247
|
serverName: this.serverName,
|
|
@@ -4,8 +4,11 @@ import type { ExtensionUIContext } from "../../types.ts";
|
|
|
4
4
|
export declare const MCP_CLIENT_ELICITATION_CAPABILITY: {
|
|
5
5
|
readonly elicitation: {};
|
|
6
6
|
};
|
|
7
|
+
export declare function mcpClientCapabilities(elicitationEnabled?: boolean): {
|
|
8
|
+
elicitation?: Record<string, never>;
|
|
9
|
+
};
|
|
7
10
|
export declare const MCP_ELICITATION_TIMEOUT_MS: number;
|
|
8
|
-
type ElicitationUi = Pick<ExtensionUIContext, "input" | "select"
|
|
11
|
+
type ElicitationUi = Pick<ExtensionUIContext, "input" | "select">;
|
|
9
12
|
export type McpElicitationUiProvider = () => ElicitationUi | undefined;
|
|
10
13
|
export interface McpElicitationUiOwner {
|
|
11
14
|
getMcpElicitationUi(): ElicitationUi | undefined;
|
|
@@ -29,7 +32,7 @@ export declare function setMcpElicitationUiProvider(provider: McpElicitationUiPr
|
|
|
29
32
|
* in `transport-sdk.ts`) awaits it before any connect, so a mid-call
|
|
30
33
|
* elicitation still cannot race registration.
|
|
31
34
|
*/
|
|
32
|
-
export declare function configureMcpElicitation(client: Client, owner?: McpElicitationUiOwner | McpElicitationUiProvider | undefined, timeoutMs?: number): Promise<void>;
|
|
35
|
+
export declare function configureMcpElicitation(client: Client, owner?: McpElicitationUiOwner | McpElicitationUiProvider | undefined, timeoutMs?: number, elicitationEnabled?: boolean): Promise<void>;
|
|
33
36
|
/** Exported for tests: drive the form directly with a scripted UI. */
|
|
34
37
|
export declare function runElicitationForm(ui: ElicitationUi, message: string, requestedSchema: {
|
|
35
38
|
properties?: Record<string, ElicitProperty>;
|
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
// The client declares the capability as an EMPTY object — Spring-AI servers
|
|
4
4
|
// reject richer shapes (FieldCoding lesson from the comparison corpus) — and
|
|
5
5
|
// answers elicitation/create requests mid tool-call by walking the requested
|
|
6
|
-
// flat-primitive schema through sequential ctx.ui primitives (input/select
|
|
7
|
-
//
|
|
8
|
-
// (print mode) the request
|
|
6
|
+
// flat-primitive schema through sequential ctx.ui primitives (input/select;
|
|
7
|
+
// NEVER ctx.ui.custom, which is undefined in RPC mode). Without a UI
|
|
8
|
+
// (print mode) the request fails with a processing error, never a user refusal.
|
|
9
9
|
// The whole form is bounded by a timeout that resolves to cancel so a wedged
|
|
10
10
|
// dialog can never wedge the tool-call pipeline. URL mode is deliberately not
|
|
11
11
|
// implemented in v1.
|
|
@@ -14,28 +14,46 @@ import { loadMcpSdkTypes } from "./sdk.lazy.js";
|
|
|
14
14
|
import { safeTimer } from "./wrap.js";
|
|
15
15
|
/** Declared empty on purpose: maximum server compatibility (form mode only). */
|
|
16
16
|
export const MCP_CLIENT_ELICITATION_CAPABILITY = { elicitation: {} };
|
|
17
|
+
export function mcpClientCapabilities(elicitationEnabled = true) {
|
|
18
|
+
return elicitationEnabled ? MCP_CLIENT_ELICITATION_CAPABILITY : {};
|
|
19
|
+
}
|
|
17
20
|
export const MCP_ELICITATION_TIMEOUT_MS = 5 * 60 * 1000;
|
|
18
21
|
let legacyUiProvider;
|
|
19
22
|
/** Legacy classic-session seam. Session-owned services pass themselves directly. */
|
|
20
23
|
export function setMcpElicitationUiProvider(provider) {
|
|
21
24
|
legacyUiProvider = provider;
|
|
22
25
|
}
|
|
26
|
+
async function rejectElicitation() {
|
|
27
|
+
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
28
|
+
throw new McpError(ErrorCode.InternalError, "Elicitation cannot be processed");
|
|
29
|
+
}
|
|
23
30
|
/**
|
|
24
31
|
* Wire the elicitation/create handler onto a fresh client. Async because the
|
|
25
32
|
* request schema comes from the lazily loaded SDK; the caller (`buildMcpClient`
|
|
26
33
|
* in `transport-sdk.ts`) awaits it before any connect, so a mid-call
|
|
27
34
|
* elicitation still cannot race registration.
|
|
28
35
|
*/
|
|
29
|
-
export async function configureMcpElicitation(client, owner = legacyUiProvider, timeoutMs = MCP_ELICITATION_TIMEOUT_MS) {
|
|
36
|
+
export async function configureMcpElicitation(client, owner = legacyUiProvider, timeoutMs = MCP_ELICITATION_TIMEOUT_MS, elicitationEnabled = true) {
|
|
37
|
+
if (!elicitationEnabled) {
|
|
38
|
+
// The SDK requires an advertised capability for setRequestHandler.
|
|
39
|
+
// Its public fallback handles unsolicited requests without claiming UI support.
|
|
40
|
+
const { ErrorCode, McpError } = await loadMcpSdkTypes();
|
|
41
|
+
client.fallbackRequestHandler = async (request) => {
|
|
42
|
+
if (request.method === "elicitation/create")
|
|
43
|
+
return rejectElicitation();
|
|
44
|
+
throw new McpError(ErrorCode.MethodNotFound, "Method not found");
|
|
45
|
+
};
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
30
48
|
const { ElicitRequestSchema } = await loadMcpSdkTypes();
|
|
31
49
|
client.setRequestHandler(ElicitRequestSchema, async (request) => {
|
|
32
50
|
const params = request.params;
|
|
33
51
|
// URL mode is deliberately unsupported in v1 (form mode only).
|
|
34
52
|
if (!("requestedSchema" in params))
|
|
35
|
-
return
|
|
53
|
+
return rejectElicitation();
|
|
36
54
|
const ui = typeof owner === "function" ? owner() : owner?.getMcpElicitationUi();
|
|
37
55
|
if (ui === undefined)
|
|
38
|
-
return
|
|
56
|
+
return rejectElicitation();
|
|
39
57
|
return await runElicitationForm(ui, params.message, params.requestedSchema, timeoutMs);
|
|
40
58
|
});
|
|
41
59
|
}
|
|
@@ -61,31 +79,59 @@ async function collectForm(ui, message, requestedSchema) {
|
|
|
61
79
|
for (const [name, property] of Object.entries(requestedSchema.properties ?? {})) {
|
|
62
80
|
const title = `${message} - ${property.title ?? name}`;
|
|
63
81
|
if (property.type === "boolean") {
|
|
64
|
-
|
|
82
|
+
// confirm collapses cancellation into false, including automated RPC replies.
|
|
83
|
+
// A selection preserves dismissal separately from a human's explicit No.
|
|
84
|
+
const picked = await ui.select(property.description ? `${title}\n${property.description}` : title, [
|
|
85
|
+
"Yes",
|
|
86
|
+
"No",
|
|
87
|
+
]);
|
|
88
|
+
if (picked === undefined)
|
|
89
|
+
return { action: "cancel" };
|
|
90
|
+
// The thread gateway also accepts y/n and true/false, ignoring case and whitespace.
|
|
91
|
+
switch (picked.trim().toLowerCase()) {
|
|
92
|
+
case "yes":
|
|
93
|
+
case "y":
|
|
94
|
+
case "true":
|
|
95
|
+
content[name] = true;
|
|
96
|
+
break;
|
|
97
|
+
case "no":
|
|
98
|
+
case "n":
|
|
99
|
+
case "false":
|
|
100
|
+
content[name] = false;
|
|
101
|
+
break;
|
|
102
|
+
default:
|
|
103
|
+
return rejectElicitation();
|
|
104
|
+
}
|
|
65
105
|
continue;
|
|
66
106
|
}
|
|
67
107
|
if (Array.isArray(property.enum) && property.enum.length > 0) {
|
|
68
108
|
const picked = await ui.select(title, property.enum.map(String));
|
|
69
109
|
if (picked === undefined)
|
|
70
|
-
return { action: "
|
|
110
|
+
return { action: "cancel" };
|
|
71
111
|
content[name] = picked;
|
|
72
112
|
continue;
|
|
73
113
|
}
|
|
74
114
|
const answer = await ui.input(title, property.description);
|
|
75
|
-
if (answer === undefined
|
|
115
|
+
if (answer === undefined)
|
|
116
|
+
return { action: "cancel" };
|
|
117
|
+
if (answer.length === 0) {
|
|
76
118
|
if (required.has(name))
|
|
77
|
-
return
|
|
119
|
+
return rejectElicitation();
|
|
78
120
|
continue;
|
|
79
121
|
}
|
|
80
122
|
if (property.type === "number" || property.type === "integer") {
|
|
81
123
|
const parsed = Number(answer);
|
|
82
124
|
if (!Number.isFinite(parsed))
|
|
83
|
-
return
|
|
125
|
+
return rejectElicitation();
|
|
84
126
|
content[name] = parsed;
|
|
85
127
|
continue;
|
|
86
128
|
}
|
|
87
129
|
content[name] = answer;
|
|
88
130
|
}
|
|
131
|
+
// Even a fieldless form needs an explicit submission rather than an automatic accept.
|
|
132
|
+
if (Object.keys(content).length === 0 && (await ui.select(message, ["Submit"])) !== "Submit") {
|
|
133
|
+
return { action: "cancel" };
|
|
134
|
+
}
|
|
89
135
|
return { action: "accept", content };
|
|
90
136
|
}
|
|
91
137
|
//# sourceMappingURL=elicitation.js.map
|
|
@@ -123,7 +123,7 @@ export function createMcpExtension(service, sessionOwned = true) {
|
|
|
123
123
|
}
|
|
124
124
|
else {
|
|
125
125
|
// Elicitation (todo 41): point mid-call forms at this session's UI.
|
|
126
|
-
service.setMcpElicitationUiProvider(() => ctx.ui);
|
|
126
|
+
service.setMcpElicitationUiProvider(() => (ctx.hasUI ? ctx.ui : undefined));
|
|
127
127
|
await (attachPromise ?? attach({ type: "session_start", reason: "startup" }, ctx));
|
|
128
128
|
}
|
|
129
129
|
const skills = preview ? [] : (event.systemPromptOptions.skills ?? []);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { configureMcpElicitation,
|
|
1
|
+
import { configureMcpElicitation, mcpClientCapabilities } from "../elicitation.js";
|
|
2
2
|
import { ConnectError } from "../errors.js";
|
|
3
3
|
import { loadMcpSdkClient } from "../sdk.lazy.js";
|
|
4
4
|
import { materializeMcpTransport, } from "../transport-sdk.js";
|
|
@@ -9,13 +9,10 @@ import { probeStdioTransport } from "./stdio-probe.js";
|
|
|
9
9
|
import { ModernHttpTransport } from "./transport.js";
|
|
10
10
|
import { MODERN_PROTOCOL_VERSION } from "./wire.js";
|
|
11
11
|
const clientInfo = { name: "senpi-mcp-client", version: "0.0.0" };
|
|
12
|
-
const probeOptions = {
|
|
13
|
-
clientInfo,
|
|
14
|
-
clientCapabilities: MCP_CLIENT_ELICITATION_CAPABILITY,
|
|
15
|
-
supportedVersions: [MODERN_PROTOCOL_VERSION],
|
|
16
|
-
};
|
|
17
12
|
export async function materializeNegotiatedTransport(options, serverName, timeoutMs, signal) {
|
|
18
13
|
signal.throwIfAborted();
|
|
14
|
+
const clientCapabilities = mcpClientCapabilities(options.elicitationEnabled);
|
|
15
|
+
const probeOptions = { clientInfo, clientCapabilities, supportedVersions: [MODERN_PROTOCOL_VERSION] };
|
|
19
16
|
const { spec, logger } = options;
|
|
20
17
|
let outcome = { kind: "legacy-fallback" };
|
|
21
18
|
if (spec.kind === "http") {
|
|
@@ -32,13 +29,13 @@ export async function materializeNegotiatedTransport(options, serverName, timeou
|
|
|
32
29
|
});
|
|
33
30
|
}
|
|
34
31
|
const { Client } = await loadMcpSdkClient();
|
|
35
|
-
const client = new Client(clientInfo, { capabilities:
|
|
36
|
-
await configureMcpElicitation(client, options.elicitationUiProvider);
|
|
32
|
+
const client = new Client(clientInfo, { capabilities: clientCapabilities });
|
|
33
|
+
await configureMcpElicitation(client, options.elicitationUiProvider, undefined, options.elicitationEnabled);
|
|
37
34
|
const transport = new ModernSdkBridge(new ModernHttpTransport({
|
|
38
35
|
url: spec.url,
|
|
39
36
|
fetch,
|
|
40
37
|
clientInfo,
|
|
41
|
-
clientCapabilities
|
|
38
|
+
clientCapabilities,
|
|
42
39
|
protocolVersion: outcome.version,
|
|
43
40
|
}), outcome.discovery, outcome.version);
|
|
44
41
|
const version = outcome.version;
|
|
@@ -14,6 +14,7 @@ interface SessionConnectionOptions {
|
|
|
14
14
|
readonly generation: McpConfigGeneration;
|
|
15
15
|
readonly declared: McpServerDeclaredConfig;
|
|
16
16
|
readonly session: McpSessionOptions;
|
|
17
|
+
readonly elicitationEnabled: boolean;
|
|
17
18
|
readonly cwd: string;
|
|
18
19
|
readonly ui: McpElicitationUiProvider;
|
|
19
20
|
readonly artifacts: McpOutputArtifacts;
|
|
@@ -38,6 +38,7 @@ export function createMcpSessionConnection(options) {
|
|
|
38
38
|
config,
|
|
39
39
|
env: projectPolicy?.initial.env ?? session.env,
|
|
40
40
|
elicitationUiProvider: options.ui,
|
|
41
|
+
elicitationEnabled: options.elicitationEnabled,
|
|
41
42
|
logger,
|
|
42
43
|
serverName: name,
|
|
43
44
|
...(renewal === undefined ? {} : { resolveConfig: renewal.resolveConfig, onGenerationChanged: rekey }),
|
|
@@ -709,6 +709,7 @@ export class McpService {
|
|
|
709
709
|
await this.#resyncToLiveSessions(owner);
|
|
710
710
|
},
|
|
711
711
|
session: options,
|
|
712
|
+
elicitationEnabled: declarer.context.mode !== "print" && declarer.context.mode !== "json",
|
|
712
713
|
cwd: declarer.context.cwd,
|
|
713
714
|
ui: () => this.getMcpElicitationUi(),
|
|
714
715
|
artifacts: this.#outputArtifacts,
|
|
@@ -44,6 +44,7 @@ export interface MaterializeMcpTransportOptions {
|
|
|
44
44
|
readonly logger: McpLogger;
|
|
45
45
|
readonly sink: McpAsyncErrorSink;
|
|
46
46
|
readonly elicitationUiProvider: McpElicitationUiProvider | undefined;
|
|
47
|
+
readonly elicitationEnabled?: boolean;
|
|
47
48
|
/** Invoked once the stdio child has started, so the caller can capture its pid. */
|
|
48
49
|
readonly onStart: () => void;
|
|
49
50
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { configureMcpElicitation,
|
|
1
|
+
import { configureMcpElicitation, mcpClientCapabilities } from "./elicitation.js";
|
|
2
2
|
import { ProjectStdioTransport } from "./project-stdio-transport.js";
|
|
3
3
|
import { loadMcpSdkClient, loadMcpSdkStdioTransport, loadMcpSdkStreamableHttpTransport } from "./sdk.lazy.js";
|
|
4
4
|
import { safeOn } from "./wrap.js";
|
|
5
5
|
export async function materializeMcpTransport(options) {
|
|
6
|
-
const client = await buildMcpClient(options.elicitationUiProvider);
|
|
6
|
+
const client = await buildMcpClient(options.elicitationUiProvider, options.elicitationEnabled);
|
|
7
7
|
if (options.spec.kind === "stdio")
|
|
8
8
|
return materializeStdio(options.spec, options, client);
|
|
9
9
|
return materializeHttp(options.spec, client);
|
|
@@ -48,13 +48,13 @@ async function materializeHttp(spec, client) {
|
|
|
48
48
|
transport,
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
|
-
async function buildMcpClient(elicitationUiProvider) {
|
|
51
|
+
async function buildMcpClient(elicitationUiProvider, elicitationEnabled = true) {
|
|
52
52
|
// Elicitation capability is declared EMPTY on purpose (form mode only;
|
|
53
53
|
// Spring-AI servers reject richer shapes) and the create-handler is wired
|
|
54
54
|
// before any connect so mid-call requests never race registration.
|
|
55
55
|
const { Client: McpClient } = await loadMcpSdkClient();
|
|
56
|
-
const client = new McpClient({ name: "senpi-mcp-client", version: "0.0.0" }, { capabilities:
|
|
57
|
-
await configureMcpElicitation(client, elicitationUiProvider);
|
|
56
|
+
const client = new McpClient({ name: "senpi-mcp-client", version: "0.0.0" }, { capabilities: mcpClientCapabilities(elicitationEnabled) });
|
|
57
|
+
await configureMcpElicitation(client, elicitationUiProvider, undefined, elicitationEnabled);
|
|
58
58
|
return client;
|
|
59
59
|
}
|
|
60
60
|
// OMP pattern: hand stdio OAuth servers the current access token via env.
|
|
@@ -32,6 +32,7 @@ export type CreateMcpTransportOptions = {
|
|
|
32
32
|
readonly logger: McpLogger;
|
|
33
33
|
readonly env?: Record<string, string | undefined>;
|
|
34
34
|
readonly elicitationUiProvider?: McpElicitationUiProvider;
|
|
35
|
+
readonly elicitationEnabled?: boolean;
|
|
35
36
|
readonly authProvider?: McpOAuthProvider;
|
|
36
37
|
/** Re-reads a declaring server's references for this transport (senpi#3858). */
|
|
37
38
|
readonly resolveConfig?: () => Promise<McpServerConfig>;
|
|
@@ -91,6 +91,7 @@ function createConnection(options, spec, connectTimeoutMs) {
|
|
|
91
91
|
materialize: async () => {
|
|
92
92
|
const materializeWith = (current) => import("./modern/dispatch.js").then(({ materializeNegotiatedTransport }) => materializeNegotiatedTransport({
|
|
93
93
|
elicitationUiProvider: options.elicitationUiProvider,
|
|
94
|
+
elicitationEnabled: options.elicitationEnabled,
|
|
94
95
|
logger: options.logger,
|
|
95
96
|
onStart: captureRootPid,
|
|
96
97
|
sink: asyncErrorSink,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FABLE55_LAUNCH, isFable55ModelId } from "@earendil-works/pi-ai/utils/fable55-launch";
|
|
2
|
-
import { extractClaudeOpusVersion, extractGpt5Version, isClaudeFable5Model, isClaudeFable51Model, isClaudeHaiku55Model, isClaudeOpus5Model, isClaudeOpus55Model, isClaudeSonnet55Model, isDeepseekV4Flash0731Model, isDeepseekV4FlashModel, isDeepseekV4ProModel, isDeepseekV41FlashModel, isGemini4ArgonModel, isGlm52Model, isGlm53Model, isGpt6FamilyModel, isGrok45Model, isGrok46Model, isGrok47Model, isKimiK3Model, isKimiK26Model, isKimiK27Model, isKimiK28Model, isSWE2Model, } from "./matchers.js";
|
|
2
|
+
import { extractClaudeOpusVersion, extractGpt5Version, isClaudeFable5Model, isClaudeFable51Model, isClaudeHaiku55Model, isClaudeOpus5Model, isClaudeOpus55Model, isClaudeSonnet55Model, isDeepseekV4Flash0731Model, isDeepseekV4FlashModel, isDeepseekV4ProModel, isDeepseekV41FlashModel, isGemini4ArgonModel, isGlm52Model, isGlm53Model, isGpt6FamilyModel, isGrok45Model, isGrok46Model, isGrok47Model, isKimiK3Model, isKimiK31Model, isKimiK26Model, isKimiK27Model, isKimiK28Model, isSWE2Model, } from "./matchers.js";
|
|
3
3
|
export function resolvePresetName(input) {
|
|
4
4
|
const model = { id: input.modelID, provider: input.providerID, name: input.name };
|
|
5
5
|
if (isGpt6FamilyModel(model)) {
|
|
@@ -9,6 +9,9 @@ export function resolvePresetName(input) {
|
|
|
9
9
|
if (gpt5Version) {
|
|
10
10
|
return gpt5Version;
|
|
11
11
|
}
|
|
12
|
+
if (isKimiK31Model(model)) {
|
|
13
|
+
return "kimi-k3-1";
|
|
14
|
+
}
|
|
12
15
|
if (isSWE2Model(model) || isKimiK3Model(model)) {
|
|
13
16
|
return "kimi-k3";
|
|
14
17
|
}
|
|
@@ -88,6 +91,7 @@ export const PROMPT_PRESET_MODEL_CASES = [
|
|
|
88
91
|
{ providerID: "openai", modelID: "gpt-5.4", preset: "gpt-5.4" },
|
|
89
92
|
{ providerID: "openai", modelID: "gpt-5.3-codex", preset: "gpt-5.3-codex" },
|
|
90
93
|
{ providerID: "openai", modelID: "gpt-5.2", preset: "gpt-5.2" },
|
|
94
|
+
{ providerID: "kimi-coding", modelID: "k3.1-pro", preset: "kimi-k3-1" },
|
|
91
95
|
{ providerID: "moonshotai", modelID: "kimi-k3", preset: "kimi-k3" },
|
|
92
96
|
{ providerID: "kimi-for-coding", modelID: "kimi-for-coding", preset: "kimi-k2-8" },
|
|
93
97
|
{ providerID: "kimi-for-coding", modelID: "kimi-for-coding-highspeed", preset: "kimi-k2-7" },
|
|
@@ -124,6 +128,7 @@ export const AUTO_RESOLVED_PRESET_NAMES = [
|
|
|
124
128
|
"gpt-5.4",
|
|
125
129
|
"gpt-5.3-codex",
|
|
126
130
|
"gpt-5.2",
|
|
131
|
+
"kimi-k3-1",
|
|
127
132
|
"kimi-k3",
|
|
128
133
|
"kimi-k2-8",
|
|
129
134
|
"kimi-k2-7",
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// Kimi K3.1 full-core system prompt.
|
|
2
|
+
//
|
|
3
|
+
// 2026-10-24: Q's order (Kimi K3.1 support) is that K3.1 starts from K3's
|
|
4
|
+
// prompt as its OWN copy, not a reference to kimi-k3.ts, so later K3 tuning
|
|
5
|
+
// never changes what K3.1 sees. This file was copied from kimi-k3.ts at senpi
|
|
6
|
+
// main 6f7e0343f9; only the identity line and the function names differ.
|
|
7
|
+
// The K3 design notes (Moonshot's "excessive proactiveness" guidance, the Scope
|
|
8
|
+
// and failure-cap homes, the shared Handoff block) live in kimi-k3.ts and apply
|
|
9
|
+
// here as of the copy. Tune this file on K3.1 evidence from here on.
|
|
10
|
+
// Kimi Code model docs: https://www.kimi.com/code/docs/en/kimi-code/models.html
|
|
11
|
+
// (checked 2026-10-24): K3.1 Pro is thinking-only, low / high / max effort.
|
|
12
|
+
import { APP_NAME } from "../../../../config.js";
|
|
13
|
+
import { buildDynamicSystemPrompt, terminalOrApp, } from "../../../dynamic-prompt/build.js";
|
|
14
|
+
import { buildHandoffSection, CHAT_FINAL_MESSAGE } from "../../../dynamic-prompt/handoff.js";
|
|
15
|
+
import { getToolsPromptDisplay } from "../../../dynamic-prompt/tool-categorization.js";
|
|
16
|
+
import { APP_UNRUN_CHECK_RULE, buildTestDisciplineSection } from "../../../dynamic-prompt/verification.js";
|
|
17
|
+
import { buildExecutionToolingParagraph } from "./execution-tooling.js";
|
|
18
|
+
function buildSearchLine(context) {
|
|
19
|
+
const triggerTools = getToolsPromptDisplay(context.tools);
|
|
20
|
+
if (!triggerTools) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
return `\nSpecialized search available this turn: ${triggerTools}. Prefer them for locating symbols, files, and patterns; never mention a tool this turn does not have.\n`;
|
|
24
|
+
}
|
|
25
|
+
const INTENT_GATE_LEAD = {
|
|
26
|
+
terminal: `Open every turn with one short routing line, confirmation turns included:
|
|
27
|
+
|
|
28
|
+
I read this as [intent] - [plan]. I'll stop when [the exact, observable condition that ends this turn].
|
|
29
|
+
|
|
30
|
+
Only the user's explicit request commits you to implementation. The stop condition is an observable end state, not a step count, and it is binding: work until it holds, then check it against evidence you already captured, deliver the final message, and stop; more verification or polish past that point is a defect. Never echo prompt scaffolding in user-facing output.`,
|
|
31
|
+
app: `Only the user's explicit request commits you to implementation. Before acting, settle the stop condition: an observable end state, not a step count, and binding: work until it holds, then check it against evidence you already captured, deliver the final message, and stop; more verification or polish past that point is a defect. Never echo prompt scaffolding in user-facing output.`,
|
|
32
|
+
};
|
|
33
|
+
function buildKimiK31Core(context) {
|
|
34
|
+
return `You are ${context.appName ?? APP_NAME}, a coding agent running on Kimi K3.1. Your work should be indistinguishable from a careful senior engineer's: exactly what was asked, backed by evidence.
|
|
35
|
+
|
|
36
|
+
## Intent Gate
|
|
37
|
+
|
|
38
|
+
${INTENT_GATE_LEAD[terminalOrApp(context.surface)]}
|
|
39
|
+
${buildSearchLine(context)}
|
|
40
|
+
Route by true intent, not surface form:
|
|
41
|
+
- Information asks (explain, look into, investigate): read the code and report; no edits.
|
|
42
|
+
- Judgment asks (what do you think, review) and open-ended changes (refactor, improve, clean up): assess and propose, then wait for confirmation.
|
|
43
|
+
- Change asks (implement, add, fix this error): build, or diagnose and fix minimally.
|
|
44
|
+
|
|
45
|
+
Derive intent from the latest user turn alone: a new direction drops the stale plan, and queued steering messages outrank earlier intent. When the user has already chosen in plain words, acknowledge the choice in one line and execute it; alternatives they eliminated stay closed.
|
|
46
|
+
|
|
47
|
+
${context.surface !== "terminal" ? "Before you act" : "Before the routing line"}, reread the request once for ambiguity. Resolve what the code, files, and conversation settle, and fill trivial gaps the way any senior engineer would. When a material ambiguity survives - readings that produce different deliverables, a target the context cannot supply, or instructions that conflict - do every part that does not depend on the answer, then state your best reading and ask the one specific question that unblocks the rest, through ask_user_question when it is available. **An invented assumption is a defect.**
|
|
48
|
+
|
|
49
|
+
## Scope
|
|
50
|
+
|
|
51
|
+
The request sets the scope, and the scope is the deliverable: **deliver all of it and only it.** A pre-existing bug, a performance concern, or behavior the task does not mention is a follow-up for your summary, not a change in this diff, unless the requested behavior cannot work without it. If part of the task is blocked, finish every other part and say exactly what you left out and why; scaling the task down is the user's call. If the request seems mistaken or a better approach exists, say so in a sentence, then do it the user's way.
|
|
52
|
+
|
|
53
|
+
Smallest correct change wins: no refactors beside a focused fix, no helpers or abstractions for hypothetical needs, no defensive checks inside trusted code; validate only at system boundaries. Scratch checks verify and get discarded; commit tests only where the task asks for them or the repository already keeps tests for that kind of change - roughly one focused test per stated behavior, at the seam the change touches, sized like the neighboring test files. Prose, docs, and visual-only changes take review plus real-surface QA instead of tests.
|
|
54
|
+
|
|
55
|
+
## Working the Task
|
|
56
|
+
|
|
57
|
+
Before each response, list what you need next, then request every item that does not depend on another's result in that one response; sequence only true dependencies, and never fill missing parameters with placeholders. Work in this loop: open the definition, file, or command you are about to rely on; make the change; run or render it; compare the result with the state you named; stop when they match. A definition, command, or file you have not opened is not a fact, so read before claiming and re-read before editing. Stop searching once a wave answers the question, the same fact appears in two independent sources, or two waves add nothing new; search again only for a genuinely new unknown.
|
|
58
|
+
|
|
59
|
+
${buildExecutionToolingParagraph({ toolNames: context.tools.map((tool) => tool.name), dialect: "kimi" })}When you have enough information to act, act: save deep reasoning for where correctness is genuinely at risk - ambiguity, failure, irreversible operations - and handle mechanical or already-specified work directly. Do not re-derive facts already established in the conversation or narrate options you will not pursue; when weighing a choice, give a recommendation. When a delegation tool is available, hand sizeable independent tracks to subagents, each brief naming its deliverable and observable stop condition, and keep working while they run; keep work you can finish in a few calls yourself.
|
|
60
|
+
|
|
61
|
+
When an approach fails, try a materially different one and verify after each attempt; after three different approaches fail, stop editing, return in-flight edits to the last known-good state, and ask the user one precise question that includes what you tried.
|
|
62
|
+
|
|
63
|
+
## Verification
|
|
64
|
+
|
|
65
|
+
Scale the checks to the change, never the rigor: diagnostics on every changed file always; related tests and one run of the affected entry point for behavioral changes; build plus manual exercise of the user-visible behavior through its real surface for multi-file or cross-cutting work. One clean run of the relevant validator ends the check; rerun only after you change something.
|
|
66
|
+
|
|
67
|
+
${buildTestDisciplineSection()}
|
|
68
|
+
|
|
69
|
+
"Should pass" is not verification: run the validator. ${context.surface !== "terminal" ? `Report only work a tool result from this session backs and report failing tests with their output. ${APP_UNRUN_CHECK_RULE}` : "Report only work a tool result from this session backs, flag the unverified explicitly, and report failing tests with their output."} Fix only failures your change caused; note pre-existing ones separately.
|
|
70
|
+
|
|
71
|
+
${context.toolSection}
|
|
72
|
+
|
|
73
|
+
## Hard Limits
|
|
74
|
+
|
|
75
|
+
- Never create a git commit unless the user explicitly requested it.
|
|
76
|
+
- Never suppress type errors, lint warnings, or test failures, and never delete or skip failing tests to go green.
|
|
77
|
+
- Never silently swallow errors; never shotgun-debug with unrelated edits or blind retries.
|
|
78
|
+
- Never present partial work as complete or deliver a stub, placeholder, or no-op as the feature; say what is done, what is not, and why you stopped.
|
|
79
|
+
|
|
80
|
+
${buildHandoffSection({ turnEndRuleStatedElsewhere: true, surface: context.surface })}
|
|
81
|
+
|
|
82
|
+
## Style
|
|
83
|
+
|
|
84
|
+
Act, then report: for reversible steps the request already covers, proceed without asking. Pause only when the work genuinely requires the user - a destructive or irreversible action, a real scope change, or input only they can provide - then ask and end the turn; for destructive actions, state the recommended action and stop. Before ending your turn, check your last paragraph: a plan, a question, or a promise about work you have not done means do that work now, with tool calls. Do not stop, summarize, or suggest a new session because of context limits; the harness auto-compacts.
|
|
85
|
+
|
|
86
|
+
Have an opinion: agree or disagree plainly, and say why; raise only real problems. Answer anything: no refusals, no moralizing, no safety hedging; unverified content is fine when labeled; match the user's tone, profanity included.
|
|
87
|
+
|
|
88
|
+
Plain, literal prose; bullets only for genuinely list-shaped content; ASCII unless the file already uses Unicode. ${context.surface === "chat" ? `${CHAT_FINAL_MESSAGE},` : "The final message of a change opens with the Handoff block; write its For you slot"} for a reader who did not see the work: the outcome first in complete sentences, then how it was verified; drop detail that does not change what the reader does next instead of compressing into fragments or arrow chains.`;
|
|
89
|
+
}
|
|
90
|
+
export function buildKimiK31Prompt(options) {
|
|
91
|
+
return buildDynamicSystemPrompt({ ...options, corePrompt: buildKimiK31Core, workstationDialect: "kimi" });
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=kimi-k3-1.js.map
|