@ycodium-ai/agent-claude 0.2.3598 → 0.2.3608

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.
Files changed (2) hide show
  1. package/dist/index.js +140 -79
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -50,7 +50,9 @@ var CLAUDE_CARD = {
50
50
  // (同一会话两轮不同模型,中间一条 `setModel`)。宿主内置名片此前写 unsupported,
51
51
  // 与 adapter 自己声明给编排的 `"in-session"` 相反——那边是真的,名片是错的。
52
52
  sessionModelSwitch: "in-session",
53
- sessionOptionSwitch: "unsupported",
53
+ // 暴露的选项只有推理档(含 ultracode、max)与快速模式,都经 `applyFlagSettings` 在会话里写
54
+ // (adapter/sessionOptions.ts),换选项不重开会话,挂在进程里的子 agent 与后台任务保住。
55
+ sessionOptionSwitch: "in-session",
54
56
  runtimeModeSwitch: "in-session",
55
57
  // SDK 的 `setPermissionMode` 会话中途就能改,所以这一位也是真的。
56
58
  nativeModeSwitch: true,
@@ -22017,6 +22019,13 @@ function resolveClaudeEffort(caps, raw) {
22017
22019
  if (!descriptor || descriptor.type !== "select") return void 0;
22018
22020
  return currentSelectValue(descriptor, raw);
22019
22021
  }
22022
+ function unsupportedClaudeEffort(caps, raw) {
22023
+ const descriptor = caps.optionDescriptors.find((entry) => entry.id === "effort");
22024
+ if (!raw || raw === RETIRED_CLAUDE_EFFORT || !descriptor || descriptor.type !== "select") {
22025
+ return void 0;
22026
+ }
22027
+ return currentSelectValue(descriptor, raw) === raw ? void 0 : raw;
22028
+ }
22020
22029
  function normalizeClaudeCliEffort(effort) {
22021
22030
  if (!effort) {
22022
22031
  return void 0;
@@ -25046,10 +25055,77 @@ async function applyClaudePermissionMode(context, mode, control) {
25046
25055
  context.currentPermissionAllow = allow;
25047
25056
  }
25048
25057
 
25058
+ // src/adapter/sessionOptions.ts
25059
+ function resolveClaudeSessionOptions(input) {
25060
+ const { modelSelection, recipe } = input;
25061
+ const caps = claudeModelCapabilities(modelSelection?.model, input.catalog, recipe.customModels);
25062
+ const descriptors = caps.optionDescriptors;
25063
+ const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort");
25064
+ const effort = resolveClaudeEffort(caps, rawEffort) ?? null;
25065
+ const supports = (id2) => descriptors.some((descriptor) => descriptor.type === "boolean" && descriptor.id === id2);
25066
+ const fastMode = getModelSelectionBooleanOptionValue(modelSelection, "fastMode") === true && supports("fastMode");
25067
+ const thinking = supports("thinking") ? getModelSelectionBooleanOptionValue(modelSelection, "thinking") : void 0;
25068
+ return {
25069
+ effort: getEffectiveClaudeAgentEffort(effort) ?? void 0,
25070
+ unsupportedEffort: unsupportedClaudeEffort(caps, rawEffort),
25071
+ fastMode,
25072
+ settings: buildClaudeSessionSettings({
25073
+ thinking,
25074
+ fastMode,
25075
+ ultracode: isClaudeUltracodeEffort(effort),
25076
+ autoCompactWindow: recipe.autoCompactWindow
25077
+ })
25078
+ };
25079
+ }
25080
+ var readEffectiveEffort = (settings) => {
25081
+ if (typeof settings !== "object" || settings === null) return void 0;
25082
+ const effective = settings.effective;
25083
+ if (typeof effective !== "object" || effective === null) return void 0;
25084
+ const level = effective.effortLevel;
25085
+ return typeof level === "string" && level.length > 0 ? level : void 0;
25086
+ };
25087
+ async function applyClaudeSessionOptions(context, desired, methodPrefix, log) {
25088
+ const threadId = context.session.threadId;
25089
+ if (context.currentApiModelId !== desired.apiModelId) {
25090
+ try {
25091
+ await context.query.setModel(desired.apiModelId);
25092
+ } catch (cause) {
25093
+ throw toRequestError(threadId, `${methodPrefix}/setModel`, cause);
25094
+ }
25095
+ context.currentApiModelId = desired.apiModelId;
25096
+ }
25097
+ const effortChanged = context.currentEffort !== desired.effort;
25098
+ const patch = {
25099
+ ...diffClaudeSessionSettings(context.currentSettings, desired.settings),
25100
+ // SDK 的 Settings 类型不含 `max`,CLI 会话内照收(见上)。
25101
+ ...effortChanged ? {
25102
+ effortLevel: desired.effort ?? null
25103
+ } : {}
25104
+ };
25105
+ if (Object.keys(patch).length > 0) {
25106
+ try {
25107
+ await context.query.applyFlagSettings(patch);
25108
+ } catch (cause) {
25109
+ throw toRequestError(threadId, `${methodPrefix}/applyFlagSettings`, cause);
25110
+ }
25111
+ context.currentSettings = desired.settings;
25112
+ context.currentEffort = desired.effort;
25113
+ }
25114
+ if (!effortChanged || desired.effort === void 0 || desired.effort === "max") return;
25115
+ const requested = desired.effort;
25116
+ void context.query.getSettings?.().then((readback) => {
25117
+ const adopted = readEffectiveEffort(readback);
25118
+ if (adopted !== void 0 && adopted !== requested) {
25119
+ log.warn("claude.session.effort-readback-differs", { threadId, requested, adopted });
25120
+ }
25121
+ }).catch(() => void 0);
25122
+ }
25123
+
25049
25124
  // src/adapter/sendTurn.ts
25050
25125
  var makeSendTurn = (deps) => {
25051
25126
  const {
25052
25127
  emitter,
25128
+ log,
25053
25129
  recipe,
25054
25130
  boundInstanceId,
25055
25131
  currentModelCatalog,
@@ -25070,40 +25146,35 @@ var makeSendTurn = (deps) => {
25070
25146
  if (context.turnState && steeringTurnState === null) {
25071
25147
  await completeTurn(context, "completed");
25072
25148
  }
25073
- if (modelSelection?.model) {
25074
- const apiModelId = await resolveClaudeCliModelId({
25075
- requestedModelId: modelSelection.model,
25076
- placeholder: CLAUDE_CARD.defaultModel,
25077
- catalog: currentModelCatalog,
25078
- declared: declaredModels,
25079
- customModels: recipe.customModels,
25080
- refreshCatalog: refreshModelCatalogForSend,
25081
- refreshSucceeded: modelCatalogRefreshSucceeded
25082
- });
25083
- const turnCaps = claudeModelCapabilities(
25084
- modelSelection.model,
25085
- currentModelCatalog(),
25086
- recipe.customModels
25087
- );
25088
- if (context.currentApiModelId !== apiModelId) {
25089
- try {
25090
- await context.query.setModel(apiModelId);
25091
- } catch (cause) {
25092
- throw toRequestError(input.threadId, "turn/setModel", cause);
25093
- }
25094
- context.currentApiModelId = apiModelId;
25095
- }
25096
- context.session = {
25097
- ...context.session,
25098
- model: modelSelection.model
25099
- };
25100
- const turnEffort = resolveClaudeEffort(
25101
- turnCaps,
25102
- getModelSelectionStringOptionValue(modelSelection, "effort")
25103
- );
25104
- context.currentEffort = getEffectiveClaudeAgentEffort(turnEffort ?? null) ?? void 0;
25105
- }
25149
+ const apiModelId = modelSelection?.model && steeringTurnState === null ? await resolveClaudeCliModelId({
25150
+ requestedModelId: modelSelection.model,
25151
+ placeholder: CLAUDE_CARD.defaultModel,
25152
+ catalog: currentModelCatalog,
25153
+ declared: declaredModels,
25154
+ customModels: recipe.customModels,
25155
+ refreshCatalog: refreshModelCatalogForSend,
25156
+ refreshSucceeded: modelCatalogRefreshSucceeded
25157
+ }) : void 0;
25158
+ let unsupportedEffort;
25106
25159
  try {
25160
+ if (modelSelection?.model && apiModelId !== void 0) {
25161
+ const turnOptions = resolveClaudeSessionOptions({
25162
+ modelSelection,
25163
+ catalog: currentModelCatalog(),
25164
+ recipe
25165
+ });
25166
+ await applyClaudeSessionOptions(
25167
+ context,
25168
+ { apiModelId, effort: turnOptions.effort, settings: turnOptions.settings },
25169
+ "turn",
25170
+ log
25171
+ );
25172
+ unsupportedEffort = turnOptions.unsupportedEffort;
25173
+ context.session = {
25174
+ ...context.session,
25175
+ model: modelSelection.model
25176
+ };
25177
+ }
25107
25178
  if (input.interactionMode === "plan") {
25108
25179
  await applyClaudePermissionMode(context, "plan", {
25109
25180
  method: "turn/setPermissionMode"
@@ -25113,6 +25184,12 @@ var makeSendTurn = (deps) => {
25113
25184
  method: "turn/setPermissionMode"
25114
25185
  });
25115
25186
  }
25187
+ if (steeringTurnState === null && context.turnState?.synthetic === true) {
25188
+ await completeTurn(context, "completed");
25189
+ }
25190
+ if (requireSession(input.threadId) !== context) {
25191
+ throw new Error(`Claude session replaced: ${input.threadId}`);
25192
+ }
25116
25193
  } catch (cause) {
25117
25194
  const rejected = Object.assign(
25118
25195
  cause instanceof Error ? cause : new Error(String(cause)),
@@ -25167,6 +25244,12 @@ var makeSendTurn = (deps) => {
25167
25244
  context
25168
25245
  });
25169
25246
  for (const warning of turnText.warnings) await emitRuntimeWarning(context, warning);
25247
+ if (unsupportedEffort !== void 0 && modelSelection?.model) {
25248
+ await emitRuntimeWarning(
25249
+ context,
25250
+ `${modelSelection.model} does not support the "${unsupportedEffort}" reasoning level, so this turn uses the model's default level. Your saved choice is unchanged.`
25251
+ );
25252
+ }
25170
25253
  const message = await buildUserMessageFromTurn({
25171
25254
  text: turnText,
25172
25255
  attachments: input.attachments,
@@ -25960,7 +26043,7 @@ var makeSessionLifecycle = (deps) => {
25960
26043
  context.spawnEnvironment,
25961
26044
  desired.spawnEnvironment
25962
26045
  );
25963
- const reusable = !context.stopped && context.session.status !== "closed" && context.session.cwd === input.cwd && sameWorkingDirectories(context.additionalDirectories, desired.additionalDirectories) && context.session.runtimeMode === input.runtimeMode && context.basePermissionMode === desired.permissionMode && context.launchEffort === desired.effectiveEffort && context.sessionSkills?.pluginDir === input.skills?.pluginDir && (resumeTarget === void 0 || resumeTarget === context.resumeSessionId) && changedEnvironmentKeys.length === 0;
26046
+ const reusable = !context.stopped && context.session.status !== "closed" && context.session.cwd === input.cwd && sameWorkingDirectories(context.additionalDirectories, desired.additionalDirectories) && context.session.runtimeMode === input.runtimeMode && context.basePermissionMode === desired.permissionMode && context.sessionSkills?.pluginDir === input.skills?.pluginDir && (resumeTarget === void 0 || resumeTarget === context.resumeSessionId) && changedEnvironmentKeys.length === 0;
25964
26047
  if (!reusable) {
25965
26048
  if (changedEnvironmentKeys.length > 0) {
25966
26049
  log.info("claude.session.environment-changed", {
@@ -25970,23 +26053,16 @@ var makeSessionLifecycle = (deps) => {
25970
26053
  }
25971
26054
  return void 0;
25972
26055
  }
25973
- if (context.currentApiModelId !== desired.apiModelId) {
25974
- try {
25975
- await context.query.setModel(desired.apiModelId);
25976
- } catch (cause) {
25977
- throw toRequestError(context.session.threadId, "session/setModel", cause);
25978
- }
25979
- context.currentApiModelId = desired.apiModelId;
25980
- }
25981
- const settingsPatch = diffClaudeSessionSettings(context.currentSettings, desired.settings);
25982
- if (settingsPatch) {
25983
- try {
25984
- await context.query.applyFlagSettings(settingsPatch);
25985
- } catch (cause) {
25986
- throw toRequestError(context.session.threadId, "session/applyFlagSettings", cause);
25987
- }
25988
- context.currentSettings = desired.settings;
25989
- }
26056
+ await applyClaudeSessionOptions(
26057
+ context,
26058
+ {
26059
+ apiModelId: desired.apiModelId,
26060
+ effort: desired.effectiveEffort,
26061
+ settings: desired.settings
26062
+ },
26063
+ "session",
26064
+ log
26065
+ );
25990
26066
  const updatedAt = nowIso();
25991
26067
  context.session = {
25992
26068
  ...context.session,
@@ -26138,24 +26214,15 @@ var makeStartSession = (deps) => {
26138
26214
  refreshCatalog: () => modelCatalog.refresh({ force: true }),
26139
26215
  refreshSucceeded: () => modelCatalog.lastRefreshOk()
26140
26216
  }) : void 0;
26141
- const caps = claudeModelCapabilities(
26142
- modelSelection?.model,
26143
- currentModelCatalog(),
26144
- recipe.customModels
26145
- );
26146
- const descriptors = caps.optionDescriptors;
26147
- const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort");
26148
- const effort = resolveClaudeEffort(caps, rawEffort) ?? null;
26149
- const fastModeSupported = descriptors.some(
26150
- (descriptor) => descriptor.type === "boolean" && descriptor.id === "fastMode"
26151
- );
26152
- const thinkingSupported = descriptors.some(
26153
- (descriptor) => descriptor.type === "boolean" && descriptor.id === "thinking"
26154
- );
26155
- const fastMode = getModelSelectionBooleanOptionValue(modelSelection, "fastMode") === true && fastModeSupported;
26156
- const thinking = thinkingSupported ? getModelSelectionBooleanOptionValue(modelSelection, "thinking") : void 0;
26157
- const ultracode = isClaudeUltracodeEffort(effort);
26158
- const effectiveEffort = getEffectiveClaudeAgentEffort(effort);
26217
+ const {
26218
+ effort: effectiveEffort,
26219
+ fastMode,
26220
+ settings
26221
+ } = resolveClaudeSessionOptions({
26222
+ modelSelection,
26223
+ catalog: currentModelCatalog(),
26224
+ recipe
26225
+ });
26159
26226
  const permissionMode = claudePermissionModeFor(input.runtimeMode, input.nativeModeId);
26160
26227
  if (launchArgPermissionMode !== void 0) {
26161
26228
  log.warn("claude.launchArgs.permissionModeIgnored", {
@@ -26172,12 +26239,6 @@ var makeStartSession = (deps) => {
26172
26239
  reason: "permission mode follows the permission seat; --dangerously-skip-permissions was removed"
26173
26240
  });
26174
26241
  }
26175
- const settings = buildClaudeSessionSettings({
26176
- thinking,
26177
- fastMode,
26178
- ultracode,
26179
- autoCompactWindow: recipe.autoCompactWindow
26180
- });
26181
26242
  const workingDirectories = claudeWorkingDirectories(input.cwd, input.additionalDirectories);
26182
26243
  const additionalDirectories = workingDirectories.directories;
26183
26244
  const spawnEnvironment = {
@@ -26364,8 +26425,7 @@ var makeStartSession = (deps) => {
26364
26425
  currentApiModelId: apiModelId,
26365
26426
  // 上下文长度只信 SDK 结果里报的那个数,起步时不猜。
26366
26427
  lastKnownContextWindow: void 0,
26367
- currentEffort: effectiveEffort ?? void 0,
26368
- launchEffort: effectiveEffort ?? void 0,
26428
+ currentEffort: effectiveEffort,
26369
26429
  sessionSkills: input.skills,
26370
26430
  spawnEnvironment,
26371
26431
  additionalDirectories,
@@ -29352,6 +29412,7 @@ function createClaudeAdapter(recipe, host, options) {
29352
29412
  });
29353
29413
  const { sendTurn } = makeSendTurn({
29354
29414
  emitter,
29415
+ log: options?.log ?? host.log,
29355
29416
  recipe,
29356
29417
  boundInstanceId,
29357
29418
  attachments: options?.attachments,
@@ -29542,7 +29603,7 @@ var executors = [
29542
29603
  ];
29543
29604
  var index_default = definePlugin({
29544
29605
  id: "agent-claude",
29545
- apiVersion: 48,
29606
+ apiVersion: 49,
29546
29607
  executors,
29547
29608
  activate(ctx) {
29548
29609
  capturedAttachments = ctx.attachments;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/agent-claude",
3
- "version": "0.2.3598",
3
+ "version": "0.2.3608",
4
4
  "description": "Claude executor: Claude Code CLI via @anthropic-ai/claude-agent-sdk.",
5
5
  "keywords": [
6
6
  "ycodium",
@@ -24,9 +24,9 @@
24
24
  "@types/node": "24.12.4",
25
25
  "esbuild": "0.28.1",
26
26
  "vite-plus": "0.2.2",
27
- "@ycodium-ai/plugin-api": "0.2.3598",
28
- "ycodium-composer-tokens": "0.0.0",
27
+ "@ycodium-ai/plugin-api": "0.2.3608",
29
28
  "ycodium-executor-testing": "0.0.0",
29
+ "ycodium-composer-tokens": "0.0.0",
30
30
  "ycodium-jsonl-stream": "0.0.0"
31
31
  },
32
32
  "ycodium": {