@ycodium-ai/plugin-im 0.2.3252 → 0.2.3254

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 CHANGED
@@ -261,7 +261,7 @@ conversation and is left out when none has arrived since the plugin started, as
261
261
  A picture goes as `image` only when it is PNG, JPEG or GIF within 10 MB (`imageMimeTypes`).
262
262
 
263
263
  Chat commands: `/stop`, `/continue`, `/status`, `/version`, `/new`, `/sessions`, `/resume`, `/history [count]`, `/model`,
264
- `/plan`, `/repo`, `/group`, `/team`, `/thread`, `/help`, `/panel`. In a chat with no project
264
+ `/reasoning`, `/plan`, `/repo`, `/group`, `/team`, `/thread`, `/help`, `/panel`. In a chat with no project
265
265
  `/sessions`, `/resume` and the team commands answer with the project picker. `/version` still answers. `/sessions` and `/resume` only list and
266
266
  switch threads this plugin opened, since the host lets a plugin send only into
267
267
  its own threads. `/continue` calls `threads.turnQueue.resume` for the chat's thread
@@ -274,6 +274,8 @@ resumes a paused queue from the chat; it is not `/resume`, which already switche
274
274
 
275
275
  On Lark, Telegram, and the WeCom smart bot, `/panel` sends a command panel, and `/help` stays text and ends with a pointer to it. WeCom App does not implement the panel surface, so `/panel` answers with the text list and `/help` does not mention `/panel`. Lark cards and Telegram inline keyboards show all command buttons. The WeCom smart bot uses a template card from `src/wecomPanel.ts`; its main menu is limited to six buttons. Commands that do not fit are listed in `/help` and can be typed into the chat. Commands that take an argument (a thread, a project, a model) open a second view on the same message with a Back button. These lists let you reach every option by paging: Lark and Telegram show eight items per page, and WeCom shows three, leaving room for Back, Previous, and Next. A tap on the WeCom card updates that same card; when the update cannot be applied, `src/panelController.ts` posts a new card and the old one stops accepting taps. A busy placeholder is not drawn on that card: it stays as it is until the next interactive view. Telegram buttons carry only a short `pn:<version>:<index>` token (`callback_data` is capped at 64 bytes); the action stays in memory and a tap on an older keyboard version counts as expired. Each card keeps its own view stack in memory (`src/panelController.ts`), so after a restart an old card only answers that it has expired. A tap runs the same handler as the typed command and waits in the same per-chat queue as typed messages. Another platform opts in by implementing the optional `panel` surface on its adapter (`src/adapter.ts`).
276
276
 
277
+ `/reasoning` shows the current model's reasoning efforts; `/reasoning <value>` or `/reasoning <number>` switches it. Numbers follow the available values at the time you send the command, so send `/reasoning` first to check the choices. See [Model and Plan Mode](../../docs/user/im-bots.md#model-and-plan-mode) for details.
278
+
277
279
  `/team` uses the chat's selected project. It reads the roster from the `team` plugin and
278
280
  each text message invokes `startGoal` with a stable request ID derived from the bot,
279
281
  platform, chat, and inbound message ID. A successful goal binds the chat to the lead's
package/dist/index.js CHANGED
@@ -126699,7 +126699,18 @@ var readChatPatch = (data) => {
126699
126699
  else if (isRecord(data["model"])) {
126700
126700
  const instanceId = nonEmpty3(data["model"]["instanceId"]);
126701
126701
  const model = nonEmpty3(data["model"]["model"]);
126702
- if (instanceId !== null && model !== null) patch.model = { instanceId, model };
126702
+ if (instanceId !== null && model !== null) {
126703
+ const options = data["model"]["options"];
126704
+ patch.model = {
126705
+ instanceId,
126706
+ model,
126707
+ ...Array.isArray(options) ? {
126708
+ options: options.flatMap(
126709
+ (entry) => isRecord(entry) && nonEmpty3(entry["id"]) !== null && (typeof entry["value"] === "string" || typeof entry["value"] === "boolean") ? [{ id: String(entry["id"]), value: entry["value"] }] : []
126710
+ )
126711
+ } : {}
126712
+ };
126713
+ }
126703
126714
  }
126704
126715
  if (data["preset"] === null) patch.preset = null;
126705
126716
  else if (nonEmpty3(data["preset"]) !== null) patch.preset = nonEmpty3(data["preset"]);
@@ -128340,7 +128351,7 @@ var makeChatSetup = (core, deps) => {
128340
128351
  };
128341
128352
 
128342
128353
  // src/commands.ts
128343
- import { threadOrNull as threadOrNull2 } from "@ycodium-ai/plugin-api";
128354
+ import { threadOrNull as threadOrNull3 } from "@ycodium-ai/plugin-api";
128344
128355
 
128345
128356
  // ../../node_modules/.pnpm/effect@4.0.0-beta.103_patch_hash=78523ded7c3dfc3efd3cec0247f4960d00eaa3d3c96a2077457694a4d8b453c6/node_modules/effect/dist/Pipeable.js
128346
128357
  var pipeArguments = (self2, args2) => {
@@ -133558,7 +133569,7 @@ var ParsedChatCommand = Union2([
133558
133569
  SimpleChatCommand,
133559
133570
  Struct({ kind: Literal2("sessions"), arg: optionalKey2(String4) }),
133560
133571
  Struct({
133561
- kind: Literals(["resume", "model", "repo", "version"]),
133572
+ kind: Literals(["resume", "model", "reasoning", "repo", "version"]),
133562
133573
  arg: String4
133563
133574
  }),
133564
133575
  Struct({ kind: Literal2("history"), count: NullOr(Number5) }),
@@ -133631,6 +133642,13 @@ var parseChatCommand = (input) => {
133631
133642
  }
133632
133643
  const model = modelArgument(input.text, input.chinese);
133633
133644
  if (model !== void 0) return { kind: "model", arg: model };
133645
+ const reasoning = commandArgument(
133646
+ trimmed,
133647
+ input.chinese,
133648
+ /^\/reasoning(?:\s+([\s\S]*))?$/i,
133649
+ /^思考强度(?:\s+([\s\S]*))?$/
133650
+ );
133651
+ if (reasoning !== void 0) return { kind: "reasoning", arg: reasoning };
133634
133652
  const preset = trimmed.match(/^\/preset(?:\s+([\s\S]*))?$/iu);
133635
133653
  if (preset !== null)
133636
133654
  return {
@@ -133668,6 +133686,7 @@ var helpText = (t, options = {}) => [
133668
133686
  t("help.history", HISTORY_COUNTS),
133669
133687
  t("help.syncNote"),
133670
133688
  t("help.model"),
133689
+ t("help.reasoning"),
133671
133690
  t("help.preset"),
133672
133691
  t("help.plan"),
133673
133692
  t("help.repo"),
@@ -133847,10 +133866,188 @@ ${body}`);
133847
133866
  };
133848
133867
  };
133849
133868
 
133869
+ // src/reasoningCommand.ts
133870
+ import { modelSelectionStringOption as modelSelectionStringOption2 } from "@ycodium-ai/plugin-api/executor";
133871
+
133872
+ // src/currentModel.ts
133873
+ import { threadOrNull as threadOrNull2 } from "@ycodium-ai/plugin-api";
133874
+
133875
+ // src/botModel.ts
133876
+ var resolveDefaultModel = async (bot, chatModel, projectDefault, providers, knownInstances) => {
133877
+ if (chatModel !== null) return chatModel;
133878
+ if (bot.defaultModel !== void 0) {
133879
+ const instances = knownInstances === void 0 ? await providers.list({}).catch(() => null) : knownInstances;
133880
+ if (!isModelCatalogComplete(instances) || modelCatalogHas(modelChoices(instances ?? []), bot.defaultModel)) {
133881
+ return bot.defaultModel;
133882
+ }
133883
+ }
133884
+ return projectDefault;
133885
+ };
133886
+
133887
+ // src/threadUsable.ts
133888
+ var threadUsable = (binding, thread) => thread !== null && thread.archivedAt == null && thread.projectId === binding.projectId;
133889
+
133890
+ // src/currentModel.ts
133891
+ var makeCurrentModelResolver = (core) => {
133892
+ const { host } = core;
133893
+ return async (binding, {
133894
+ instances,
133895
+ onReadError = (error) => {
133896
+ throw error;
133897
+ }
133898
+ } = {}) => {
133899
+ const chat = chatOf(core.state, chatKeyOf(binding));
133900
+ if (chat.threadId !== null) {
133901
+ const thread = await threadOrNull2(host.threads, chat.threadId, { archived: "include" }).catch(
133902
+ onReadError
133903
+ );
133904
+ if (threadUsable(binding, thread))
133905
+ return { selection: thread.modelSelection, threadId: chat.threadId };
133906
+ }
133907
+ if (chat.model !== null) return { selection: chat.model, threadId: null };
133908
+ const project = binding.projectId === "" ? null : await host.projects.get({ projectId: binding.projectId }).catch(onReadError);
133909
+ return {
133910
+ selection: await resolveDefaultModel(
133911
+ binding,
133912
+ chat.model,
133913
+ project?.defaultModelSelection ?? null,
133914
+ host.providers.instances,
133915
+ instances
133916
+ ),
133917
+ threadId: null
133918
+ };
133919
+ };
133920
+ };
133921
+ var saveModelSelection = async (core, binding, threadId, model) => {
133922
+ if (threadId !== null) {
133923
+ try {
133924
+ await core.host.threads.update({
133925
+ requestId: crypto.randomUUID(),
133926
+ threadId,
133927
+ modelSelection: model
133928
+ });
133929
+ } catch (error) {
133930
+ core.host.log.warn("chat could not switch the thread model", {
133931
+ error: describeError(error)
133932
+ });
133933
+ return false;
133934
+ }
133935
+ }
133936
+ core.commit("chat-updated", { chatKey: chatKeyOf(binding), model });
133937
+ return true;
133938
+ };
133939
+
133940
+ // src/reasoningOption.ts
133941
+ import { modelOptionLabelKind, modelSelectionStringOption } from "@ycodium-ai/plugin-api/executor";
133942
+ var isReasoningOption = (id) => modelOptionLabelKind(id) !== void 0;
133943
+ var reasoningOption = (model) => model.options.find((option2) => isReasoningOption(option2.id) && option2.values.length > 0);
133944
+ var selectedReasoning = (selection) => {
133945
+ const option2 = selection?.options?.find((entry) => isReasoningOption(entry.id));
133946
+ if (option2 === void 0) return void 0;
133947
+ const value2 = modelSelectionStringOption(selection, option2.id);
133948
+ return value2 === void 0 ? void 0 : { id: option2.id, value: value2 };
133949
+ };
133950
+
133951
+ // src/reasoningCommand.ts
133952
+ var isDefaultArgument = (arg, chinese) => arg.toLowerCase() === "default" || chinese && arg === "\u9ED8\u8BA4";
133953
+ var makeReasoningCommand = (core, currentModel) => {
133954
+ const { host, t, deliver } = core;
133955
+ const readOptions = async (binding) => {
133956
+ const resolved = await currentModel(binding);
133957
+ const selection = resolved.selection;
133958
+ const catalog = selection === null ? null : await host.providers.models.list({ instanceId: selection.instanceId });
133959
+ const model = catalog?.models.find((entry) => entry.slug === selection?.model);
133960
+ return { ...resolved, option: model === void 0 ? void 0 : reasoningOption(model) };
133961
+ };
133962
+ return async (binding, arg) => {
133963
+ const resolved = await readOptions(binding).catch(() => null);
133964
+ if (resolved === null) {
133965
+ host.log.warn("chat could not read reasoning options");
133966
+ await deliver(binding, t("reasoning.readFailed"));
133967
+ return;
133968
+ }
133969
+ const { selection, threadId, option: option2 } = resolved;
133970
+ if (selection === null) {
133971
+ await deliver(binding, t("reasoning.noModel"));
133972
+ return;
133973
+ }
133974
+ const wanted = arg.trim();
133975
+ if (isDefaultArgument(wanted, t.language === "zh-CN")) {
133976
+ if (selectedReasoning(selection) === void 0) {
133977
+ await deliver(binding, t(threadId === null ? "reasoning.resetNext" : "reasoning.resetNow"));
133978
+ return;
133979
+ }
133980
+ const next2 = {
133981
+ ...selection,
133982
+ options: (selection.options ?? []).filter((entry) => !isReasoningOption(entry.id))
133983
+ };
133984
+ if (!await saveModelSelection(core, binding, threadId, next2)) {
133985
+ await deliver(binding, t("reasoning.setFailed"));
133986
+ return;
133987
+ }
133988
+ await deliver(binding, t(threadId === null ? "reasoning.resetNext" : "reasoning.resetNow"));
133989
+ return;
133990
+ }
133991
+ if (option2 === void 0) {
133992
+ await deliver(binding, t("reasoning.unsupported"));
133993
+ return;
133994
+ }
133995
+ if (arg === "") {
133996
+ const current = modelSelectionStringOption2(selection, option2.id);
133997
+ const listed = current !== void 0 && option2.values.includes(current);
133998
+ const title = current === void 0 ? "reasoning.listTitleDefault" : listed ? "reasoning.listTitle" : "reasoning.listTitlePlain";
133999
+ const text3 = [
134000
+ ...current === void 0 ? [] : [t(listed ? "reasoning.current" : "reasoning.currentUnlisted", { value: current })],
134001
+ ...formatChatChoices(
134002
+ option2.values,
134003
+ (entry) => entry,
134004
+ (entry) => entry === current,
134005
+ {
134006
+ title: t(title),
134007
+ more: (count) => t("reasoning.more", { count }),
134008
+ footer: t("reasoning.usage")
134009
+ }
134010
+ )
134011
+ ].join("\n").trim();
134012
+ await deliver(binding, text3);
134013
+ return;
134014
+ }
134015
+ const value2 = option2.values.find((entry) => entry === wanted) ?? pickChatChoice(wanted, option2.values, (entry, needle) => entry.toLowerCase() === needle);
134016
+ if (value2 === null) {
134017
+ const shown = option2.values.slice(0, CHAT_CHOICE_LIST_MAX);
134018
+ await deliver(
134019
+ binding,
134020
+ [
134021
+ /^\d+$/.test(wanted) ? t("reasoning.numberOutOfRange", { number: wanted, max: shown.length }) : t("reasoning.notFound", { query: arg }),
134022
+ t("reasoning.usage"),
134023
+ t("reasoning.choices", { values: shown.join(" / ") }),
134024
+ ...option2.values.length > shown.length ? [t("reasoning.more", { count: option2.values.length - shown.length })] : []
134025
+ ].join("\n")
134026
+ );
134027
+ return;
134028
+ }
134029
+ const next = {
134030
+ ...selection,
134031
+ options: [
134032
+ ...(selection.options ?? []).filter((entry) => !isReasoningOption(entry.id)),
134033
+ { id: option2.id, value: value2 }
134034
+ ]
134035
+ };
134036
+ if (!await saveModelSelection(core, binding, threadId, next)) {
134037
+ await deliver(binding, t("reasoning.setFailed"));
134038
+ return;
134039
+ }
134040
+ await deliver(
134041
+ binding,
134042
+ t(threadId === null ? "reasoning.setNext" : "reasoning.setNow", { value: value2 })
134043
+ );
134044
+ };
134045
+ };
134046
+
133850
134047
  // package.json
133851
134048
  var package_default = {
133852
134049
  name: "@ycodium-ai/plugin-im",
133853
- version: "0.2.3252",
134050
+ version: "0.2.3254",
133854
134051
  description: "Talk to your agents from Telegram, WeCom, Lark, or WeChat (experimental).",
133855
134052
  keywords: [
133856
134053
  "im",
@@ -133949,6 +134146,7 @@ var makeCommands = (core, deps) => {
133949
134146
  const { handleModel, handlePlan } = deps.modelPlan;
133950
134147
  const { openPanel } = deps;
133951
134148
  const handleHistory = makeHistoryCommand(core);
134149
+ const handleReasoning = makeReasoningCommand(core, deps.modelPlan.resolveCurrentModel);
133952
134150
  const targetOf = (binding) => chatOf(core.state, chatKeyOf(binding)).target;
133953
134151
  const executeCommand = async (binding, command, senderId = null, chatKind = void 0) => {
133954
134152
  const chatKey = chatKeyOf(binding);
@@ -134010,6 +134208,9 @@ var makeCommands = (core, deps) => {
134010
134208
  case "model":
134011
134209
  await handleModel(binding, command.arg);
134012
134210
  return;
134211
+ case "reasoning":
134212
+ await handleReasoning(binding, command.arg);
134213
+ return;
134013
134214
  case "preset":
134014
134215
  await deps.handlePreset(binding, command);
134015
134216
  return;
@@ -134040,7 +134241,7 @@ var makeCommands = (core, deps) => {
134040
134241
  );
134041
134242
  return;
134042
134243
  }
134043
- const thread = await threadOrNull2(host.threads, threadId);
134244
+ const thread = await threadOrNull3(host.threads, threadId);
134044
134245
  const running = isSessionRunning(thread?.session?.status);
134045
134246
  await deliver(
134046
134247
  binding,
@@ -134090,7 +134291,7 @@ var makeCommands = (core, deps) => {
134090
134291
  await deliver(binding, t("command.stopNoSession"));
134091
134292
  return;
134092
134293
  }
134093
- const thread = await threadOrNull2(host.threads, threadId);
134294
+ const thread = await threadOrNull3(host.threads, threadId);
134094
134295
  const activeTurnId = thread?.session?.activeTurnId ?? null;
134095
134296
  if (activeTurnId === null) {
134096
134297
  await deliver(binding, t("command.stopNoTurn"));
@@ -135529,7 +135730,7 @@ var makeImCore = (input) => {
135529
135730
  };
135530
135731
 
135531
135732
  // src/conclusionDelivery.ts
135532
- import { threadOrNull as threadOrNull3 } from "@ycodium-ai/plugin-api";
135733
+ import { threadOrNull as threadOrNull4 } from "@ycodium-ai/plugin-api";
135533
135734
 
135534
135735
  // src/abortableSleep.ts
135535
135736
  var abortableSleep = (ms, signal) => new Promise((resolve2, reject) => {
@@ -135657,13 +135858,13 @@ ${text3}` : text3;
135657
135858
  const sleep4 = (ms) => abortableSleep(ms, stopped.signal).catch(() => void 0);
135658
135859
  const retryFor = (threadId, owed = ALWAYS_OWED) => ({
135659
135860
  sleep: sleep4,
135660
- shouldContinue: async () => !disposed && owed() && await threadOrNull3(core.host.threads, threadId) !== null
135861
+ shouldContinue: async () => !disposed && owed() && await threadOrNull4(core.host.threads, threadId) !== null
135661
135862
  });
135662
135863
  return {
135663
135864
  completed,
135664
135865
  retryFor,
135665
135866
  prepareConclusion: async (threadId, turnId, successful) => {
135666
- const thread = await threadOrNull3(core.host.threads, threadId);
135867
+ const thread = await threadOrNull4(core.host.threads, threadId);
135667
135868
  const final = thread === null ? void 0 : await latestMessage(
135668
135869
  core.host.threads,
135669
135870
  threadId,
@@ -146365,11 +146566,12 @@ var en_default = {
146365
146566
  new: "\xB7 /new \u2014 forget the current session; the next message starts a new one",
146366
146567
  team: "\xB7 /team \u2014 give this project's team a goal with each message; use /repo to pick the project first",
146367
146568
  thread: "\xB7 /thread \u2014 go back to a normal session",
146368
- aliases: "Chinese shortcuts (\u505C / \u7EE7\u7EED\u53D1\u9001 / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u4F1A\u8BDD\u5386\u53F2 / \u6362\u6A21\u578B / \u8BA1\u5212\u6A21\u5F0F / \u6362\u9879\u76EE / \u5EFA\u7FA4 / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD) work when the reply language is Chinese.",
146569
+ aliases: "Chinese shortcuts (\u505C / \u7EE7\u7EED\u53D1\u9001 / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u4F1A\u8BDD\u5386\u53F2 / \u6362\u6A21\u578B / \u601D\u8003\u5F3A\u5EA6 / \u8BA1\u5212\u6A21\u5F0F / \u6362\u9879\u76EE / \u5EFA\u7FA4 / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD) work when the reply language is Chinese.",
146369
146570
  sessions: "\xB7 /sessions \u2014 list this project's sessions; add a project number from /repo to list the ones this bot opened in another project",
146370
146571
  resume: "\xB7 /resume number-or-id-prefix \u2014 switch sessions; one from another project switches the project too",
146371
146572
  history: "\xB7 /history [count] \u2014 preview recent messages in the current session, in private chats only (default {{defaultCount}}, maximum {{maxCount}})",
146372
146573
  model: "\xB7 /model \u2014 see the model this chat uses; /model number or /model instance/model switches it",
146574
+ reasoning: "\xB7 /reasoning \u2014 see the reasoning effort for this chat's current model; /reasoning value or /reasoning number switches it; /reasoning default resets it to the model default",
146373
146575
  preset: "\xB7 /preset \u2014 see the preset this chat uses for new sessions; /preset number or /preset name-or-id switches it; /preset none clears the chat choice",
146374
146576
  plan: "\xB7 /plan \u2014 toggle plan mode (the agent proposes a plan instead of acting); /plan on, /plan off set it",
146375
146577
  panel: "Send /panel to open the command panel with a button for every command.",
@@ -146377,6 +146579,28 @@ var en_default = {
146377
146579
  group: "\xB7 /group name \u2014 Lark only: the bot creates a group and adds you (bots on other platforms cannot)",
146378
146580
  syncNote: "\xB7 After a private chat attaches a session, web user text and final assistant text sync here (groups never sync)."
146379
146581
  },
146582
+ reasoning: {
146583
+ current: "Current reasoning effort: {{value}}",
146584
+ currentUnlisted: "Current reasoning effort: {{value}} (no longer in the list; it stays in effect until you change it)",
146585
+ resetNow: "Reasoning effort reset to the model default. The current session uses it from the next turn; new sessions in this chat use it too.",
146586
+ resetNext: "Reasoning effort reset to the model default. New sessions in this chat will use it.",
146587
+ notFound: '"{{query}}" is not an available reasoning effort.',
146588
+ numberOutOfRange: "Number {{number}} is out of range; choose 1\u2013{{max}}.",
146589
+ listTitle: "Available reasoning efforts (\u2605 current):",
146590
+ listTitleDefault: "Available reasoning efforts (none chosen; the model default is used):",
146591
+ more: "{{count}} more not shown.",
146592
+ usage: "Usage: /reasoning \u2014 see the reasoning effort for this chat's current model; /reasoning value or /reasoning number switches it; /reasoning default resets it to the model default.",
146593
+ choices: "Choices: {{values}}.",
146594
+ unsupported: "The current model does not support switching the reasoning effort.",
146595
+ readFailed: "Could not read the reasoning options. Try again in a moment.",
146596
+ setFailed: "Switching the reasoning effort failed. Try again in a moment.",
146597
+ setNow: "Reasoning effort set to {{value}}. The current session uses it from the next turn; new sessions in this chat use it too.",
146598
+ setNext: "Reasoning effort set to {{value}}. New sessions in this chat will use it.",
146599
+ cleared: "The new model does not support the previous reasoning effort ({{value}}). It was cleared; the model default will be used.",
146600
+ noModel: "This chat has no model yet. Pick one with /model first.",
146601
+ switchReadFailed: "Could not read the new model's reasoning efforts, so the model was not switched. Try again in a moment.",
146602
+ listTitlePlain: "Available reasoning efforts:"
146603
+ },
146380
146604
  history: {
146381
146605
  usage: "Usage: /history [count] \u2014 1 to {{maxCount}} (larger numbers count as {{maxCount}}), default {{defaultCount}}.",
146382
146606
  directOnly: "In a group this would show the session to everyone. Send /history in a private chat with the bot.",
@@ -147295,11 +147519,12 @@ var zh_CN_default = {
147295
147519
  new: "\xB7 /new \u2014\u2014 \u5FD8\u6389\u5F53\u524D\u4F1A\u8BDD\uFF0C\u4E0B\u4E00\u53E5\u5F00\u65B0\u7684",
147296
147520
  team: "\xB7 /team \u2014\u2014 \u6BCF\u6761\u6D88\u606F\u90FD\u7ED9\u8FD9\u4E2A\u9879\u76EE\u7684\u56E2\u961F\u5F00\u4E00\u4E2A\u76EE\u6807\uFF1B\u5148\u7528 /repo \u9009\u9879\u76EE",
147297
147521
  thread: "\xB7 /thread \u2014\u2014 \u5207\u56DE\u666E\u901A\u4F1A\u8BDD",
147298
- aliases: "\u4E2D\u6587\u4E5F\u884C\uFF1A\u505C / \u7EE7\u7EED\u53D1\u9001 / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u4F1A\u8BDD\u5386\u53F2 / \u6362\u6A21\u578B / \u8BA1\u5212\u6A21\u5F0F / \u6362\u9879\u76EE / \u5EFA\u7FA4 / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD\u3002",
147522
+ aliases: "\u4E2D\u6587\u4E5F\u884C\uFF1A\u505C / \u7EE7\u7EED\u53D1\u9001 / \u72B6\u6001 / \u65B0\u5BF9\u8BDD / \u4F1A\u8BDD\u5217\u8868 / \u5207\u6362\u4F1A\u8BDD / \u4F1A\u8BDD\u5386\u53F2 / \u6362\u6A21\u578B / \u601D\u8003\u5F3A\u5EA6 / \u8BA1\u5212\u6A21\u5F0F / \u6362\u9879\u76EE / \u5EFA\u7FA4 / \u6362\u56E2\u961F / \u6362\u5BF9\u8BDD\u3002",
147299
147523
  sessions: "\xB7 /sessions \u2014\u2014 \u5217\u51FA\u672C\u9879\u76EE\u7684\u4F1A\u8BDD\uFF1B\u52A0 /repo \u91CC\u7684\u9879\u76EE\u7F16\u53F7\uFF0C\u5217\u51FA\u672C\u673A\u5668\u4EBA\u5728\u522B\u7684\u9879\u76EE\u5F00\u8FC7\u7684",
147300
147524
  resume: "\xB7 /resume \u7F16\u53F7\u6216 id \u5F00\u5934 \u2014\u2014 \u5207\u4F1A\u8BDD\uFF1B\u522B\u7684\u9879\u76EE\u7684\u4F1A\u8BDD\u4F1A\u8FDE\u540C\u9879\u76EE\u4E00\u8D77\u5207",
147301
147525
  history: "\xB7 /history [\u6570\u91CF] \u2014\u2014 \u4EC5\u79C1\u804A\uFF1A\u67E5\u770B\u5F53\u524D\u4F1A\u8BDD\u6700\u8FD1\u7684\u6D88\u606F\uFF08\u9ED8\u8BA4 {{defaultCount}} \u6761\uFF0C\u6700\u591A {{maxCount}} \u6761\uFF09",
147302
147526
  model: "\xB7 /model \u2014\u2014 \u770B\u8FD9\u4E2A\u804A\u5929\u7528\u7684\u6A21\u578B\uFF1B/model \u7F16\u53F7 \u6216 /model \u5B9E\u4F8B/\u6A21\u578B \u5207\u6362",
147527
+ reasoning: "\xB7 /reasoning \u2014\u2014 \u770B\u8FD9\u4E2A\u804A\u5929\u5F53\u524D\u6A21\u578B\u7684\u601D\u8003\u5F3A\u5EA6\uFF1B/reasoning \u53D6\u503C \u6216 /reasoning \u7F16\u53F7 \u5207\u6362\uFF1B/reasoning default \u6062\u590D\u6A21\u578B\u9ED8\u8BA4",
147303
147528
  preset: "\xB7 /preset \u2014\u2014 \u770B\u8FD9\u4E2A\u804A\u5929\u65B0\u4F1A\u8BDD\u7528\u7684\u9884\u8BBE\uFF1B/preset \u7F16\u53F7 \u6216 /preset \u540D\u5B57\u6216 id \u5207\u6362\uFF1B/preset none \u6E05\u6389\u804A\u5929\u9009\u62E9",
147304
147529
  plan: "\xB7 /plan \u2014\u2014 \u5F00\u5173\u8BA1\u5212\u6A21\u5F0F\uFF08agent \u5148\u51FA\u8BA1\u5212\u3001\u4E0D\u52A8\u624B\uFF09\uFF1B/plan on\u3001/plan off \u660E\u786E\u8BBE\u5B9A",
147305
147530
  panel: "\u53D1 /panel \u6253\u5F00\u53EF\u70B9\u7684\u547D\u4EE4\u9762\u677F\u3002",
@@ -147307,6 +147532,28 @@ var zh_CN_default = {
147307
147532
  group: "\xB7 /group \u7FA4\u540D \u2014\u2014 \u4EC5\u98DE\u4E66\uFF1A\u673A\u5668\u4EBA\u5EFA\u4E00\u4E2A\u7FA4\u5E76\u628A\u4F60\u62C9\u8FDB\u53BB\uFF08\u522B\u7684\u5E73\u53F0\u7684\u673A\u5668\u4EBA\u5EFA\u4E0D\u4E86\u7FA4\uFF09",
147308
147533
  syncNote: "\xB7 \u79C1\u804A\u9644\u7740\u4F1A\u8BDD\u540E\uFF0C\u7F51\u9875\u4E0A\u7684\u7528\u6237\u6587\u5B57\u4E0E\u7EC8\u6001\u52A9\u624B\u6587\u5B57\u4F1A\u540C\u6B65\u5230\u6B64\uFF08\u7FA4\u804A\u4E0D\u540C\u6B65\uFF09\u3002"
147309
147534
  },
147535
+ reasoning: {
147536
+ current: "\u5F53\u524D\u601D\u8003\u5F3A\u5EA6\uFF1A{{value}}",
147537
+ currentUnlisted: "\u5F53\u524D\u601D\u8003\u5F3A\u5EA6\uFF1A{{value}}\uFF08\u5DF2\u4E0D\u5728\u53EF\u9009\u5217\u8868\uFF0C\u6362\u6389\u4E4B\u524D\u4ECD\u751F\u6548\uFF09",
147538
+ resetNow: "\u601D\u8003\u5F3A\u5EA6\u5DF2\u6062\u590D\u4E3A\u6A21\u578B\u9ED8\u8BA4\uFF0C\u5F53\u524D\u4F1A\u8BDD\u4ECE\u4E0B\u4E00\u8F6E\u8D77\u4F7F\u7528\u5B83\uFF0C\u8FD9\u4E2A\u804A\u5929\u7684\u65B0\u4F1A\u8BDD\u4E5F\u4F7F\u7528\u5B83\u3002",
147539
+ resetNext: "\u601D\u8003\u5F3A\u5EA6\u5DF2\u6062\u590D\u4E3A\u6A21\u578B\u9ED8\u8BA4\uFF0C\u8FD9\u4E2A\u804A\u5929\u7684\u65B0\u4F1A\u8BDD\u5C06\u4F7F\u7528\u5B83\u3002",
147540
+ notFound: "\u300C{{query}}\u300D\u4E0D\u662F\u53EF\u9009\u7684\u601D\u8003\u5F3A\u5EA6\u3002",
147541
+ numberOutOfRange: "\u7F16\u53F7 {{number}} \u8D85\u51FA\u8303\u56F4\uFF0C\u53EF\u9009 1\u2013{{max}}\u3002",
147542
+ listTitle: "\u53EF\u9009\u601D\u8003\u5F3A\u5EA6\uFF08\u2605 \u5F53\u524D\uFF09\uFF1A",
147543
+ listTitleDefault: "\u53EF\u9009\u601D\u8003\u5F3A\u5EA6\uFF08\u672A\u624B\u52A8\u9009\u62E9\uFF0C\u5F53\u524D\u7528\u6A21\u578B\u9ED8\u8BA4\uFF09\uFF1A",
147544
+ more: "\u8FD8\u6709 {{count}} \u9879\u672A\u5217\u51FA\u3002",
147545
+ usage: "\u7528\u6CD5\uFF1A/reasoning \u2014\u2014 \u770B\u8FD9\u4E2A\u804A\u5929\u5F53\u524D\u6A21\u578B\u7684\u601D\u8003\u5F3A\u5EA6\uFF1B/reasoning \u53D6\u503C \u6216 /reasoning \u7F16\u53F7 \u5207\u6362\uFF1B/reasoning default \u6062\u590D\u6A21\u578B\u9ED8\u8BA4\u3002",
147546
+ choices: "\u53EF\u9009\uFF1A{{values}}\u3002",
147547
+ unsupported: "\u5F53\u524D\u6A21\u578B\u4E0D\u652F\u6301\u5207\u6362\u601D\u8003\u5F3A\u5EA6\u3002",
147548
+ readFailed: "\u6682\u65F6\u8BFB\u4E0D\u5230\u601D\u8003\u5F3A\u5EA6\u9009\u9879\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
147549
+ setFailed: "\u5207\u6362\u601D\u8003\u5F3A\u5EA6\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
147550
+ setNow: "\u601D\u8003\u5F3A\u5EA6\u5DF2\u8BBE\u4E3A {{value}}\uFF0C\u5F53\u524D\u4F1A\u8BDD\u4ECE\u4E0B\u4E00\u8F6E\u8D77\u4F7F\u7528\u5B83\uFF0C\u8FD9\u4E2A\u804A\u5929\u7684\u65B0\u4F1A\u8BDD\u4E5F\u4F7F\u7528\u5B83\u3002",
147551
+ setNext: "\u601D\u8003\u5F3A\u5EA6\u5DF2\u8BBE\u4E3A {{value}}\uFF0C\u8FD9\u4E2A\u804A\u5929\u7684\u65B0\u4F1A\u8BDD\u5C06\u4F7F\u7528\u5B83\u3002",
147552
+ cleared: "\u65B0\u6A21\u578B\u4E0D\u652F\u6301\u539F\u6765\u7684\u601D\u8003\u5F3A\u5EA6\uFF08{{value}}\uFF09\uFF0C\u5DF2\u6E05\u9664\uFF0C\u6539\u7528\u6A21\u578B\u9ED8\u8BA4\u3002",
147553
+ noModel: "\u8FD9\u4E2A\u804A\u5929\u8FD8\u6CA1\u6709\u6A21\u578B\uFF0C\u5148\u7528 /model \u9009\u4E00\u4E2A\u3002",
147554
+ switchReadFailed: "\u6682\u65F6\u8BFB\u4E0D\u5230\u65B0\u6A21\u578B\u7684\u601D\u8003\u5F3A\u5EA6\u9009\u9879\uFF0C\u6A21\u578B\u6CA1\u6709\u5207\u6362\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002",
147555
+ listTitlePlain: "\u53EF\u9009\u601D\u8003\u5F3A\u5EA6\uFF1A"
147556
+ },
147310
147557
  history: {
147311
147558
  usage: "\u7528\u6CD5\uFF1A/history [\u6570\u91CF] \u2014\u2014 1\u2013{{maxCount}} \u6761\uFF08\u8D85\u51FA\u6309 {{maxCount}} \u6761\u7B97\uFF09\uFF0C\u9ED8\u8BA4 {{defaultCount}} \u6761\u3002",
147312
147559
  directOnly: "\u5728\u7FA4\u91CC\u4F1A\u628A\u4F1A\u8BDD\u5185\u5BB9\u53D1\u7ED9\u6240\u6709\u4EBA\u3002\u5728\u4E0E\u673A\u5668\u4EBA\u7684\u79C1\u804A\u91CC\u53D1 /history\u3002",
@@ -148665,47 +148912,17 @@ var makeLarkAdapter = (deps) => {
148665
148912
  };
148666
148913
 
148667
148914
  // src/modelPlan.ts
148668
- import { threadOrNull as threadOrNull4 } from "@ycodium-ai/plugin-api";
148669
-
148670
- // src/botModel.ts
148671
- var resolveDefaultModel = async (bot, chatModel, projectDefault, providers, knownInstances) => {
148672
- if (chatModel !== null) return chatModel;
148673
- if (bot.defaultModel !== void 0) {
148674
- const instances = knownInstances === void 0 ? await providers.list({}).catch(() => null) : knownInstances;
148675
- if (!isModelCatalogComplete(instances) || modelCatalogHas(modelChoices(instances ?? []), bot.defaultModel)) {
148676
- return bot.defaultModel;
148677
- }
148678
- }
148679
- return projectDefault;
148680
- };
148681
-
148682
- // src/modelPlan.ts
148683
- var makeModelPlan = (core, deps) => {
148915
+ var makeModelPlan = (core) => {
148684
148916
  const { host, t, commit, deliver } = core;
148685
- const { threadStillUsable } = deps;
148917
+ const resolveCurrentModel = makeCurrentModelResolver(core);
148686
148918
  const currentModelOf = async (binding, instances) => {
148687
- const chat = chatOf(core.state, chatKeyOf(binding));
148688
- if (chat.threadId !== null) {
148689
- const thread = await threadOrNull4(host.threads, chat.threadId).catch(() => null);
148690
- if (thread !== null) {
148691
- return {
148692
- instanceId: thread.modelSelection.instanceId,
148693
- model: thread.modelSelection.model
148694
- };
148695
- }
148696
- }
148697
- if (chat.model !== null) return chat.model;
148698
- const project = binding.projectId === "" ? null : await host.projects.get({ projectId: binding.projectId }).catch(() => null);
148699
- return resolveDefaultModel(
148700
- binding,
148701
- chat.model,
148702
- project?.defaultModelSelection ?? null,
148703
- host.providers.instances,
148704
- instances
148705
- );
148919
+ const { selection } = await resolveCurrentModel(binding, {
148920
+ instances,
148921
+ onReadError: () => null
148922
+ });
148923
+ return selection;
148706
148924
  };
148707
148925
  const handleModel = async (binding, arg) => {
148708
- const chatKey = chatKeyOf(binding);
148709
148926
  const instances = await host.providers.instances.list({}).catch(() => null);
148710
148927
  const choices = instances === null ? [] : modelChoices(instances);
148711
148928
  if (arg === "") {
@@ -148721,25 +148938,42 @@ var makeModelPlan = (core, deps) => {
148721
148938
  await deliver(binding, t("model.notFound", { query: arg }));
148722
148939
  return;
148723
148940
  }
148724
- const selection = { instanceId: picked.instanceId, model: picked.model };
148725
- commit("chat-updated", { chatKey, model: selection });
148726
- const threadId = chatOf(core.state, chatKey).threadId;
148727
- if (threadId !== null && await threadStillUsable(binding, threadId)) {
148941
+ const { selection: current, threadId } = await resolveCurrentModel(binding, {
148942
+ instances,
148943
+ onReadError: () => null
148944
+ });
148945
+ const previous = selectedReasoning(current);
148946
+ let carried;
148947
+ if (previous !== void 0) {
148728
148948
  try {
148729
- await host.threads.update({
148730
- requestId: crypto.randomUUID(),
148731
- threadId,
148732
- modelSelection: selection
148733
- });
148734
- } catch (error) {
148735
- host.log.warn("chat could not switch the thread model", { error: describeError(error) });
148736
- await deliver(binding, t("model.setFailed"));
148949
+ const catalog = await host.providers.models.list({ instanceId: picked.instanceId });
148950
+ const model = catalog.models.find((entry) => entry.slug === picked.model);
148951
+ const option2 = model === void 0 ? void 0 : reasoningOption(model);
148952
+ if (option2 !== void 0 && option2.values.includes(previous.value))
148953
+ carried = { id: option2.id, value: previous.value };
148954
+ } catch {
148955
+ host.log.warn("chat could not read reasoning options for a model switch");
148956
+ await deliver(binding, t("reasoning.switchReadFailed"));
148737
148957
  return;
148738
148958
  }
148739
- await deliver(binding, t("model.setNow", { model: modelLabel(picked) }));
148959
+ }
148960
+ const selection = {
148961
+ instanceId: picked.instanceId,
148962
+ model: picked.model,
148963
+ ...carried === void 0 ? {} : { options: [carried] }
148964
+ };
148965
+ const cleared = previous !== void 0 && carried === void 0 ? [t("reasoning.cleared", { value: previous.value })] : [];
148966
+ if (!await saveModelSelection(core, binding, threadId, selection)) {
148967
+ await deliver(binding, t("model.setFailed"));
148740
148968
  return;
148741
148969
  }
148742
- await deliver(binding, t("model.setNext", { model: modelLabel(picked) }));
148970
+ await deliver(
148971
+ binding,
148972
+ [
148973
+ t(threadId === null ? "model.setNext" : "model.setNow", { model: modelLabel(picked) }),
148974
+ ...cleared
148975
+ ].join("\n")
148976
+ );
148743
148977
  };
148744
148978
  const handlePlan = async (binding, mode) => {
148745
148979
  if (mode === "invalid") {
@@ -148756,7 +148990,7 @@ var makeModelPlan = (core, deps) => {
148756
148990
  commit("chat-updated", { chatKey, plan: next });
148757
148991
  await deliver(binding, t(next ? "plan.on" : "plan.off"));
148758
148992
  };
148759
- return { currentModelOf, handleModel, handlePlan };
148993
+ return { currentModelOf, resolveCurrentModel, handleModel, handlePlan };
148760
148994
  };
148761
148995
 
148762
148996
  // src/notifications.ts
@@ -151954,7 +152188,7 @@ var makeTurns = (core, deps) => {
151954
152188
  const threadStillUsable = async (binding, threadId) => {
151955
152189
  try {
151956
152190
  const thread = await threadOrNull8(host.threads, threadId, { archived: "include" });
151957
- return thread !== null && thread.archivedAt == null && thread.projectId === binding.projectId;
152191
+ return threadUsable(binding, thread);
151958
152192
  } catch {
151959
152193
  return true;
151960
152194
  }
@@ -152219,7 +152453,6 @@ var makeTurns = (core, deps) => {
152219
152453
  const hasWaitingAttachments = (chatKey) => (waitingFor(chatKey, chatOf(core.state, chatKey).threadId)?.attachments.length ?? 0) > 0;
152220
152454
  return {
152221
152455
  stop: () => dispatchAbort.abort(),
152222
- threadStillUsable,
152223
152456
  ensureThread,
152224
152457
  startTurn,
152225
152458
  receiveAttachmentsOnly,
@@ -155708,7 +155941,7 @@ var makeWecomAppAdapter = (deps) => {
155708
155941
  // src/index.ts
155709
155942
  var definition = {
155710
155943
  id: "im",
155711
- apiVersion: 29,
155944
+ apiVersion: 30,
155712
155945
  // 第二个参数只给插件自己的测试夹具:换掉文件 IO 与派发重试的等待。宿主只传 ctx。
155713
155946
  activate: async (ctx, testing = {}) => {
155714
155947
  const { dispatchSleep } = testing;
@@ -155853,7 +156086,7 @@ var definition = {
155853
156086
  });
155854
156087
  const projectRows = makeProjectRows(core);
155855
156088
  const sessions = makeSessions(core, projectRows);
155856
- const modelPlan = makeModelPlan(core, turns);
156089
+ const modelPlan = makeModelPlan(core);
155857
156090
  const chatQueue = makeChatQueue(core);
155858
156091
  const panelWiring = makePanelWiring(core, {
155859
156092
  enqueueForChat: chatQueue.enqueueForChat,
package/locales/en.json CHANGED
@@ -353,11 +353,12 @@
353
353
  "new": "· /new — forget the current session; the next message starts a new one",
354
354
  "team": "· /team — give this project's team a goal with each message; use /repo to pick the project first",
355
355
  "thread": "· /thread — go back to a normal session",
356
- "aliases": "Chinese shortcuts (停 / 继续发送 / 状态 / 新对话 / 会话列表 / 切换会话 / 会话历史 / 换模型 / 计划模式 / 换项目 / 建群 / 换团队 / 换对话) work when the reply language is Chinese.",
356
+ "aliases": "Chinese shortcuts (停 / 继续发送 / 状态 / 新对话 / 会话列表 / 切换会话 / 会话历史 / 换模型 / 思考强度 / 计划模式 / 换项目 / 建群 / 换团队 / 换对话) work when the reply language is Chinese.",
357
357
  "sessions": "· /sessions — list this project's sessions; add a project number from /repo to list the ones this bot opened in another project",
358
358
  "resume": "· /resume number-or-id-prefix — switch sessions; one from another project switches the project too",
359
359
  "history": "· /history [count] — preview recent messages in the current session, in private chats only (default {{defaultCount}}, maximum {{maxCount}})",
360
360
  "model": "· /model — see the model this chat uses; /model number or /model instance/model switches it",
361
+ "reasoning": "· /reasoning — see the reasoning effort for this chat's current model; /reasoning value or /reasoning number switches it; /reasoning default resets it to the model default",
361
362
  "preset": "· /preset — see the preset this chat uses for new sessions; /preset number or /preset name-or-id switches it; /preset none clears the chat choice",
362
363
  "plan": "· /plan — toggle plan mode (the agent proposes a plan instead of acting); /plan on, /plan off set it",
363
364
  "panel": "Send /panel to open the command panel with a button for every command.",
@@ -365,6 +366,28 @@
365
366
  "group": "· /group name — Lark only: the bot creates a group and adds you (bots on other platforms cannot)",
366
367
  "syncNote": "· After a private chat attaches a session, web user text and final assistant text sync here (groups never sync)."
367
368
  },
369
+ "reasoning": {
370
+ "current": "Current reasoning effort: {{value}}",
371
+ "currentUnlisted": "Current reasoning effort: {{value}} (no longer in the list; it stays in effect until you change it)",
372
+ "resetNow": "Reasoning effort reset to the model default. The current session uses it from the next turn; new sessions in this chat use it too.",
373
+ "resetNext": "Reasoning effort reset to the model default. New sessions in this chat will use it.",
374
+ "notFound": "\"{{query}}\" is not an available reasoning effort.",
375
+ "numberOutOfRange": "Number {{number}} is out of range; choose 1–{{max}}.",
376
+ "listTitle": "Available reasoning efforts (★ current):",
377
+ "listTitleDefault": "Available reasoning efforts (none chosen; the model default is used):",
378
+ "more": "{{count}} more not shown.",
379
+ "usage": "Usage: /reasoning — see the reasoning effort for this chat's current model; /reasoning value or /reasoning number switches it; /reasoning default resets it to the model default.",
380
+ "choices": "Choices: {{values}}.",
381
+ "unsupported": "The current model does not support switching the reasoning effort.",
382
+ "readFailed": "Could not read the reasoning options. Try again in a moment.",
383
+ "setFailed": "Switching the reasoning effort failed. Try again in a moment.",
384
+ "setNow": "Reasoning effort set to {{value}}. The current session uses it from the next turn; new sessions in this chat use it too.",
385
+ "setNext": "Reasoning effort set to {{value}}. New sessions in this chat will use it.",
386
+ "cleared": "The new model does not support the previous reasoning effort ({{value}}). It was cleared; the model default will be used.",
387
+ "noModel": "This chat has no model yet. Pick one with /model first.",
388
+ "switchReadFailed": "Could not read the new model's reasoning efforts, so the model was not switched. Try again in a moment.",
389
+ "listTitlePlain": "Available reasoning efforts:"
390
+ },
368
391
  "history": {
369
392
  "usage": "Usage: /history [count] — 1 to {{maxCount}} (larger numbers count as {{maxCount}}), default {{defaultCount}}.",
370
393
  "directOnly": "In a group this would show the session to everyone. Send /history in a private chat with the bot.",
@@ -353,11 +353,12 @@
353
353
  "new": "· /new —— 忘掉当前会话,下一句开新的",
354
354
  "team": "· /team —— 每条消息都给这个项目的团队开一个目标;先用 /repo 选项目",
355
355
  "thread": "· /thread —— 切回普通会话",
356
- "aliases": "中文也行:停 / 继续发送 / 状态 / 新对话 / 会话列表 / 切换会话 / 会话历史 / 换模型 / 计划模式 / 换项目 / 建群 / 换团队 / 换对话。",
356
+ "aliases": "中文也行:停 / 继续发送 / 状态 / 新对话 / 会话列表 / 切换会话 / 会话历史 / 换模型 / 思考强度 / 计划模式 / 换项目 / 建群 / 换团队 / 换对话。",
357
357
  "sessions": "· /sessions —— 列出本项目的会话;加 /repo 里的项目编号,列出本机器人在别的项目开过的",
358
358
  "resume": "· /resume 编号或 id 开头 —— 切会话;别的项目的会话会连同项目一起切",
359
359
  "history": "· /history [数量] —— 仅私聊:查看当前会话最近的消息(默认 {{defaultCount}} 条,最多 {{maxCount}} 条)",
360
360
  "model": "· /model —— 看这个聊天用的模型;/model 编号 或 /model 实例/模型 切换",
361
+ "reasoning": "· /reasoning —— 看这个聊天当前模型的思考强度;/reasoning 取值 或 /reasoning 编号 切换;/reasoning default 恢复模型默认",
361
362
  "preset": "· /preset —— 看这个聊天新会话用的预设;/preset 编号 或 /preset 名字或 id 切换;/preset none 清掉聊天选择",
362
363
  "plan": "· /plan —— 开关计划模式(agent 先出计划、不动手);/plan on、/plan off 明确设定",
363
364
  "panel": "发 /panel 打开可点的命令面板。",
@@ -365,6 +366,28 @@
365
366
  "group": "· /group 群名 —— 仅飞书:机器人建一个群并把你拉进去(别的平台的机器人建不了群)",
366
367
  "syncNote": "· 私聊附着会话后,网页上的用户文字与终态助手文字会同步到此(群聊不同步)。"
367
368
  },
369
+ "reasoning": {
370
+ "current": "当前思考强度:{{value}}",
371
+ "currentUnlisted": "当前思考强度:{{value}}(已不在可选列表,换掉之前仍生效)",
372
+ "resetNow": "思考强度已恢复为模型默认,当前会话从下一轮起使用它,这个聊天的新会话也使用它。",
373
+ "resetNext": "思考强度已恢复为模型默认,这个聊天的新会话将使用它。",
374
+ "notFound": "「{{query}}」不是可选的思考强度。",
375
+ "numberOutOfRange": "编号 {{number}} 超出范围,可选 1–{{max}}。",
376
+ "listTitle": "可选思考强度(★ 当前):",
377
+ "listTitleDefault": "可选思考强度(未手动选择,当前用模型默认):",
378
+ "more": "还有 {{count}} 项未列出。",
379
+ "usage": "用法:/reasoning —— 看这个聊天当前模型的思考强度;/reasoning 取值 或 /reasoning 编号 切换;/reasoning default 恢复模型默认。",
380
+ "choices": "可选:{{values}}。",
381
+ "unsupported": "当前模型不支持切换思考强度。",
382
+ "readFailed": "暂时读不到思考强度选项,请稍后重试。",
383
+ "setFailed": "切换思考强度失败,请稍后重试。",
384
+ "setNow": "思考强度已设为 {{value}},当前会话从下一轮起使用它,这个聊天的新会话也使用它。",
385
+ "setNext": "思考强度已设为 {{value}},这个聊天的新会话将使用它。",
386
+ "cleared": "新模型不支持原来的思考强度({{value}}),已清除,改用模型默认。",
387
+ "noModel": "这个聊天还没有模型,先用 /model 选一个。",
388
+ "switchReadFailed": "暂时读不到新模型的思考强度选项,模型没有切换,请稍后重试。",
389
+ "listTitlePlain": "可选思考强度:"
390
+ },
368
391
  "history": {
369
392
  "usage": "用法:/history [数量] —— 1–{{maxCount}} 条(超出按 {{maxCount}} 条算),默认 {{defaultCount}} 条。",
370
393
  "directOnly": "在群里会把会话内容发给所有人。在与机器人的私聊里发 /history。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ycodium-ai/plugin-im",
3
- "version": "0.2.3252",
3
+ "version": "0.2.3254",
4
4
  "description": "Talk to your agents from Telegram, WeCom, Lark, or WeChat (experimental).",
5
5
  "keywords": [
6
6
  "im",
@@ -33,7 +33,7 @@
33
33
  "react": "19.2.6",
34
34
  "vite-plus": "0.2.2",
35
35
  "ycodium-react-test-harness": "0.0.0",
36
- "@ycodium-ai/plugin-api": "0.2.3252"
36
+ "@ycodium-ai/plugin-api": "0.2.3254"
37
37
  },
38
38
  "ycodium": {
39
39
  "plugin": "./dist/index.js",