atomix-cli 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -3056,8 +3056,14 @@ var require_adapter = __commonJS({
3056
3056
  "../atomix-core/dist/util/adapter.js"(exports2) {
3057
3057
  "use strict";
3058
3058
  Object.defineProperty(exports2, "__esModule", { value: true });
3059
- exports2.TEMPERATURE_ONE_MODELS = void 0;
3059
+ exports2.TEMPERATURE_MAX = exports2.TEMPERATURE_MIN = exports2.DEFAULT_ANTHROPIC_TEMPERATURE = exports2.TEMPERATURE_ONE_MODELS = void 0;
3060
3060
  exports2.resolveAdapter = resolveAdapter;
3061
+ exports2.openaiTemperatureCapability = openaiTemperatureCapability;
3062
+ exports2.modelForcesTemperatureOne = modelForcesTemperatureOne3;
3063
+ exports2.modelRejectsTemperature = modelRejectsTemperature3;
3064
+ exports2.modelTemperatureGatedByThinking = modelTemperatureGatedByThinking3;
3065
+ exports2.isValidTemperature = isValidTemperature3;
3066
+ exports2.assertTemperature = assertTemperature;
3061
3067
  exports2.useMaxCompletionTokens = useMaxCompletionTokens;
3062
3068
  exports2.modelForcesThinking = modelForcesThinking;
3063
3069
  exports2.forcedThinkingEffort = forcedThinkingEffort;
@@ -3106,6 +3112,60 @@ var require_adapter = __commonJS({
3106
3112
  "kimi-k2.5",
3107
3113
  "moonshotai/kimi-k2.5"
3108
3114
  ];
3115
+ var OPENAI_TEMPERATURE_NORMAL_PREFIXES = ["gpt-5-chat", "gpt-5.1-chat", "gpt-5.2-chat"];
3116
+ var OPENAI_TEMPERATURE_REJECT_EXACT = ["gpt-5"];
3117
+ var OPENAI_TEMPERATURE_REJECT_PREFIXES = [
3118
+ "o1",
3119
+ "o3",
3120
+ "o4",
3121
+ "gpt-5-mini",
3122
+ "gpt-5-nano",
3123
+ "gpt-5-20",
3124
+ // 初代及其日期快照(gpt-5-2025-08-07)
3125
+ "gpt-5-pro",
3126
+ "gpt-5.1-pro",
3127
+ "gpt-5.2-pro",
3128
+ "gpt-5-codex",
3129
+ "gpt-5.1-codex",
3130
+ "gpt-5.2-codex"
3131
+ ];
3132
+ var OPENAI_TEMPERATURE_GATED_PREFIXES = ["gpt-5.1", "gpt-5.2"];
3133
+ function bareModelName(modelName) {
3134
+ const lower = modelName.toLowerCase();
3135
+ return lower.split("/").pop() ?? lower;
3136
+ }
3137
+ function openaiTemperatureCapability(modelName) {
3138
+ const bare = bareModelName(modelName);
3139
+ if (OPENAI_TEMPERATURE_NORMAL_PREFIXES.some((p) => bare.startsWith(p)))
3140
+ return "normal";
3141
+ if (OPENAI_TEMPERATURE_REJECT_EXACT.includes(bare) || OPENAI_TEMPERATURE_REJECT_PREFIXES.some((p) => bare.startsWith(p)))
3142
+ return "reject";
3143
+ if (OPENAI_TEMPERATURE_GATED_PREFIXES.some((p) => bare.startsWith(p)))
3144
+ return "gated";
3145
+ if (bare.startsWith("gpt-5"))
3146
+ return "reject";
3147
+ return null;
3148
+ }
3149
+ function modelForcesTemperatureOne3(modelName) {
3150
+ return exports2.TEMPERATURE_ONE_MODELS.includes(modelName);
3151
+ }
3152
+ function modelRejectsTemperature3(modelName) {
3153
+ return openaiTemperatureCapability(modelName) === "reject";
3154
+ }
3155
+ function modelTemperatureGatedByThinking3(modelName) {
3156
+ return openaiTemperatureCapability(modelName) === "gated";
3157
+ }
3158
+ function isValidTemperature3(t) {
3159
+ return typeof t === "number" && Number.isFinite(t) && t >= exports2.TEMPERATURE_MIN && t <= exports2.TEMPERATURE_MAX;
3160
+ }
3161
+ exports2.DEFAULT_ANTHROPIC_TEMPERATURE = 0.7;
3162
+ exports2.TEMPERATURE_MIN = 0;
3163
+ exports2.TEMPERATURE_MAX = 2;
3164
+ function assertTemperature(t) {
3165
+ if (!isValidTemperature3(t)) {
3166
+ throw new Error(`temperature \u987B\u4E3A ${exports2.TEMPERATURE_MIN}\u2013${exports2.TEMPERATURE_MAX} \u7684\u6570\u5B57,\u6536\u5230 ${JSON.stringify(t)}`);
3167
+ }
3168
+ }
3109
3169
  var MAX_COMPLETION_TOKENS_PREFIXES = [
3110
3170
  "o1",
3111
3171
  "o3",
@@ -3299,7 +3359,8 @@ var require_apiUtil = __commonJS({
3299
3359
  model: modelName,
3300
3360
  messages: [{ role: "user", content: 'Please respond with exactly "YES" (in capital letters) to confirm this connection is working.' }],
3301
3361
  ...(0, adapter_1.useMaxCompletionTokens)(modelName) ? { max_completion_tokens: 200 } : { max_tokens: 200 },
3302
- temperature: adapter_1.TEMPERATURE_ONE_MODELS.includes(modelName) ? 1 : 0,
3362
+ // 不发 temperature:与正式请求(adapt/openai.ts)一致,交给服务端默认。之前固定发 0.0,
3363
+ // gpt-5 / o 系列等只接受默认值 1 的模型直接 400("does not support 0.0 with this model"),把可用模型挡在添加阶段
3303
3364
  stream: false
3304
3365
  }),
3305
3366
  extractContent: (response) => response.choices?.[0]?.message?.content || "",
@@ -20384,7 +20445,8 @@ var require_model = __commonJS({
20384
20445
  apiKey: config.apiKey,
20385
20446
  maxTokens: config.maxTokens || fallback.maxTokens,
20386
20447
  contextLength: config.contextLength || fallback.contextLength,
20387
- adapt: config.adapt ?? (0, adapter_1.resolveAdapter)(config.provider, config.modelName)
20448
+ adapt: config.adapt ?? (0, adapter_1.resolveAdapter)(config.provider, config.modelName),
20449
+ ...config.temperature !== void 0 ? { temperature: config.temperature } : {}
20388
20450
  };
20389
20451
  }
20390
20452
  }
@@ -20435,10 +20497,12 @@ var require_ModelManager = __commonJS({
20435
20497
  exports2.getModelManager = exports2.ModelManager = void 0;
20436
20498
  var fs15 = __importStar(require("fs"));
20437
20499
  var path15 = __importStar(require("path"));
20500
+ var adapter_1 = require_adapter();
20438
20501
  var apiUtil_1 = require_apiUtil();
20439
20502
  var savePath_1 = require_savePath();
20440
20503
  var model_1 = require_model();
20441
20504
  var log_1 = require_log();
20505
+ var EngineContext_1 = require_EngineContext();
20442
20506
  var ModelManager = class {
20443
20507
  constructor(initialConfig) {
20444
20508
  this.configPath = (0, savePath_1.getModelConfigFilePath)();
@@ -20466,6 +20530,8 @@ var require_ModelManager = __commonJS({
20466
20530
  * @param skipValidation 是否跳过API校验,默认为false
20467
20531
  */
20468
20532
  async addNewModel(config, skipValidation = false) {
20533
+ if (config.temperature !== void 0)
20534
+ this.assertProfileTemperature(config.modelName, config.temperature);
20469
20535
  const profile = (0, model_1.convertToModelProfile)(config);
20470
20536
  const existingModelIndex = this.config.modelProfiles.findIndex((p) => p.name === profile.name);
20471
20537
  if (!skipValidation) {
@@ -20494,7 +20560,7 @@ ${testResult.curlCommand}` : testResult.message;
20494
20560
  }
20495
20561
  }
20496
20562
  if (existingModelIndex !== -1) {
20497
- this.config.modelProfiles[existingModelIndex] = profile;
20563
+ this.config.modelProfiles[existingModelIndex] = { ...this.config.modelProfiles[existingModelIndex], ...profile };
20498
20564
  } else {
20499
20565
  this.config.modelProfiles.push(profile);
20500
20566
  if (this.config.modelProfiles.length === 1) {
@@ -20593,16 +20659,36 @@ ${testResult.curlCommand}` : testResult.message;
20593
20659
  };
20594
20660
  }
20595
20661
  /**
20596
- * 获取指定类型的模型配置
20662
+ * 解析指针槽位实际指向的模型标识(harness-model-v1 §2):
20663
+ * 当前会话(EngineStore.coreConfig.modelOverrides)有覆盖则用覆盖,否则用 model.conf 指针。
20664
+ * ALS 之外(无 EngineStore)读不到覆盖 = base。
20665
+ */
20666
+ resolvePointer(pointer) {
20667
+ const override = (0, EngineContext_1.getEngineStore)()?.coreConfig?.modelOverrides?.[pointer];
20668
+ if (typeof override === "string" && override)
20669
+ return { id: override, overridden: true };
20670
+ return { id: this.config.modelPointers?.[pointer] || null, overridden: false };
20671
+ }
20672
+ /**
20673
+ * 获取指定类型的模型配置(会话覆盖优先)。
20674
+ * 覆盖指向的 profile 已不存在(会话中被删)时返回 null,由调用方报错——不静默回落 base。
20597
20675
  */
20598
20676
  getModel(pointer) {
20599
- const pointerId = this.config.modelPointers?.[pointer];
20600
- if (!pointerId) {
20677
+ const { id } = this.resolvePointer(pointer);
20678
+ if (!id) {
20601
20679
  return null;
20602
20680
  }
20603
- const profile = (0, model_1.findModelProfile)(pointerId, this.config.modelProfiles);
20681
+ const profile = (0, model_1.findModelProfile)(id, this.config.modelProfiles);
20604
20682
  return profile || null;
20605
20683
  }
20684
+ /** 已配置的模型标识列表(同步;harness 解析是同步纯函数,不能等异步 getModelData)。 */
20685
+ getModelNames() {
20686
+ return this.config.modelProfiles.map((p) => p.name);
20687
+ }
20688
+ /** model.conf 的指针值(base,不含会话覆盖;同步)。 */
20689
+ getModelPointers() {
20690
+ return { main: this.config.modelPointers?.main ?? "", quick: this.config.modelPointers?.quick ?? "" };
20691
+ }
20606
20692
  /**
20607
20693
  * 获取指定类型的模型名称
20608
20694
  */
@@ -20610,6 +20696,89 @@ ${testResult.curlCommand}` : testResult.message;
20610
20696
  const profile = this.getModel(pointer);
20611
20697
  return profile ? profile.modelName : null;
20612
20698
  }
20699
+ // ===================== 温度 / profile 字段编辑(model-temperature-v1) =====================
20700
+ /** 去 apiKey 的只读视图;adapt 补齐(缺省按 provider/modelName 推断),cli 展示"协议默认"时不必再算 */
20701
+ getModelProfiles() {
20702
+ return this.config.modelProfiles.map((p) => {
20703
+ const { apiKey: _k, ...rest2 } = p;
20704
+ return { ...rest2, adapt: p.adapt ?? (0, adapter_1.resolveAdapter)(p.provider, p.modelName) };
20705
+ });
20706
+ }
20707
+ /**
20708
+ * 改单个 profile 的字段,不重跑连通性测试。`'temperature' in patch && patch.temperature === undefined` = 清除。
20709
+ * 硬约束模型(TEMPERATURE_ONE_MODELS)拒绝设温度:覆盖只会换来 4xx。
20710
+ */
20711
+ async updateModelProfile(name, patch) {
20712
+ const idx = this.config.modelProfiles.findIndex((p) => p.name === name);
20713
+ if (idx === -1)
20714
+ throw new Error(`\u6A21\u578B\u4E0D\u5B58\u5728: ${name}`);
20715
+ const next = { ...this.config.modelProfiles[idx] };
20716
+ if ("temperature" in patch) {
20717
+ if (patch.temperature === void 0)
20718
+ delete next.temperature;
20719
+ else {
20720
+ this.assertProfileTemperature(next.modelName, patch.temperature);
20721
+ next.temperature = patch.temperature;
20722
+ }
20723
+ }
20724
+ for (const k of ["maxTokens", "contextLength"]) {
20725
+ if (k in patch) {
20726
+ const v = patch[k];
20727
+ if (!Number.isInteger(v) || v <= 0)
20728
+ throw new Error(`${k} \u987B\u4E3A\u6B63\u6574\u6570,\u6536\u5230 ${JSON.stringify(v)}`);
20729
+ next[k] = v;
20730
+ }
20731
+ }
20732
+ if ("vision" in patch) {
20733
+ if (patch.vision === void 0)
20734
+ delete next.vision;
20735
+ else if (typeof patch.vision !== "boolean")
20736
+ throw new Error(`vision \u987B\u4E3A\u5E03\u5C14\u503C`);
20737
+ else
20738
+ next.vision = patch.vision;
20739
+ }
20740
+ this.config.modelProfiles[idx] = next;
20741
+ await this.saveConfig();
20742
+ const { apiKey: _k, ...rest2 } = next;
20743
+ return { ...rest2, adapt: next.adapt ?? (0, adapter_1.resolveAdapter)(next.provider, next.modelName) };
20744
+ }
20745
+ /** 范围校验 + 模型侧约束拒绝;addNewModel / updateModelProfile 共用。gpt-5 系列允许配置(thinking 关时生效),这里不挡 */
20746
+ assertProfileTemperature(modelName, t) {
20747
+ (0, adapter_1.assertTemperature)(t);
20748
+ if ((0, adapter_1.modelForcesTemperatureOne)(modelName))
20749
+ throw new Error(`\u6A21\u578B ${modelName} \u53EA\u63A5\u53D7\u9ED8\u8BA4\u6E29\u5EA6 1,\u4E0D\u80FD\u8BBE\u7F6E temperature`);
20750
+ if ((0, adapter_1.modelRejectsTemperature)(modelName))
20751
+ throw new Error(`\u6A21\u578B ${modelName} \u4E0D\u652F\u6301 temperature \u53C2\u6570(\u63A8\u7406\u6A21\u578B),\u4E0D\u80FD\u8BBE\u7F6E`);
20752
+ }
20753
+ /**
20754
+ * 请求时的温度解析(model-temperature-v1 §1.1),高者胜:
20755
+ * 1 模型侧约束:kimi 恒 1;o 系列永不发;gpt-5 系列 thinking 开(发 reasoning_effort)时不发;anthropic 协议开 thinking 不发;
20756
+ * 2 会话级覆盖(harness,经 EngineStore);3 profile.temperature;4 协议默认(anthropic 0.7,openai 不发)。
20757
+ * 返回 undefined = 请求体不带该字段。
20758
+ */
20759
+ resolveTemperature(pointer, profile, opts) {
20760
+ if ((0, adapter_1.modelForcesTemperatureOne)(profile.modelName))
20761
+ return 1;
20762
+ if ((0, adapter_1.modelRejectsTemperature)(profile.modelName))
20763
+ return void 0;
20764
+ if (opts.enableThinking && (0, adapter_1.modelTemperatureGatedByThinking)(profile.modelName))
20765
+ return void 0;
20766
+ if (opts.adapter === "anthropic" && opts.enableThinking)
20767
+ return void 0;
20768
+ const over2 = (0, EngineContext_1.getEngineStore)()?.coreConfig?.temperatureOverrides?.[pointer];
20769
+ if (over2 !== void 0 && !(0, adapter_1.isValidTemperature)(over2))
20770
+ (0, log_1.logWarn)(`temperatureOverrides.${pointer} \u975E\u6CD5(${JSON.stringify(over2)}),\u5FFD\u7565,\u6539\u7528 profile / \u9ED8\u8BA4`);
20771
+ if (profile.temperature !== void 0 && !(0, adapter_1.isValidTemperature)(profile.temperature))
20772
+ (0, log_1.logWarn)(`\u6A21\u578B ${profile.name} \u7684 temperature \u975E\u6CD5(${JSON.stringify(profile.temperature)}),\u5FFD\u7565,\u6539\u7528\u534F\u8BAE\u9ED8\u8BA4`);
20773
+ let t = (0, adapter_1.isValidTemperature)(over2) ? over2 : (0, adapter_1.isValidTemperature)(profile.temperature) ? profile.temperature : void 0;
20774
+ if (t === void 0)
20775
+ return opts.adapter === "anthropic" ? adapter_1.DEFAULT_ANTHROPIC_TEMPERATURE : void 0;
20776
+ if (opts.adapter === "anthropic" && t > 1) {
20777
+ (0, log_1.logWarn)(`temperature ${t} \u8D85\u51FA anthropic \u534F\u8BAE\u4E0A\u9650,\u6309 1 \u53D1\u9001(${profile.name})`);
20778
+ t = 1;
20779
+ }
20780
+ return t;
20781
+ }
20613
20782
  /**
20614
20783
  * 获取当前模型数据
20615
20784
  * @param showModelProfiles 是否包含详细的模型配置信息,默认为false
@@ -50733,13 +50902,15 @@ var require_cacheLLM = __commonJS({
50733
50902
  /**
50734
50903
  * 生成缓存键 - 基于消息内容生成简单hash
50735
50904
  */
50736
- generateKey(messages, systemPrompt, modelName, enableThinking = false) {
50905
+ generateKey(messages, systemPrompt, modelName, enableThinking = false, temperature) {
50737
50906
  const normalizedSystemPrompt = Array.isArray(systemPrompt) && systemPrompt.length > 0 && typeof systemPrompt[0] === "object" && "type" in systemPrompt[0] ? systemPrompt.map((item) => item.text) : systemPrompt;
50738
50907
  const content = JSON.stringify({
50739
50908
  messages: messages.map((msg) => msg.message.content),
50740
50909
  systemPrompt: normalizedSystemPrompt,
50741
50910
  modelName,
50742
- enableThinking
50911
+ enableThinking,
50912
+ temperature: temperature ?? null
50913
+ // 不同温度不共享缓存(model-temperature-v1)
50743
50914
  });
50744
50915
  return crypto_1.default.createHash("md5").update(content).digest("hex");
50745
50916
  }
@@ -50769,8 +50940,8 @@ var require_cacheLLM = __commonJS({
50769
50940
  /**
50770
50941
  * 获取缓存
50771
50942
  */
50772
- get(messages, systemPrompt, modelName, enableThinking = false) {
50773
- const key = this.generateKey(messages, systemPrompt, modelName, enableThinking);
50943
+ get(messages, systemPrompt, modelName, enableThinking = false, temperature) {
50944
+ const key = this.generateKey(messages, systemPrompt, modelName, enableThinking, temperature);
50774
50945
  const entries = this.readCacheFile();
50775
50946
  const entry = entries.find((e) => e.key === key);
50776
50947
  return entry ? entry.response : null;
@@ -50778,8 +50949,8 @@ var require_cacheLLM = __commonJS({
50778
50949
  /**
50779
50950
  * 设置缓存
50780
50951
  */
50781
- set(messages, systemPrompt, modelName, response, enableThinking = false) {
50782
- const key = this.generateKey(messages, systemPrompt, modelName, enableThinking);
50952
+ set(messages, systemPrompt, modelName, response, enableThinking = false, temperature) {
50953
+ const key = this.generateKey(messages, systemPrompt, modelName, enableThinking, temperature);
50783
50954
  let entries = this.readCacheFile();
50784
50955
  entries = entries.filter((e) => e.key !== key);
50785
50956
  entries.unshift({
@@ -50828,8 +50999,8 @@ var require_cache = __commonJS({
50828
50999
  var log_1 = require_log();
50829
51000
  var CACHE_STREAM_CHUNK_SIZE = 20;
50830
51001
  var CACHE_STREAM_DELAY = 100;
50831
- async function tryGetCachedResponse(messages, systemPromptContent, modelName, shouldStream, enableThinking, emitChunkEvents, signal) {
50832
- const cachedResponse = cacheLLM_1.llmCache.get(messages, systemPromptContent, modelName, enableThinking);
51002
+ async function tryGetCachedResponse(messages, systemPromptContent, modelName, shouldStream, enableThinking, emitChunkEvents, signal, temperature) {
51003
+ const cachedResponse = cacheLLM_1.llmCache.get(messages, systemPromptContent, modelName, enableThinking, temperature);
50833
51004
  if (!cachedResponse) {
50834
51005
  return null;
50835
51006
  }
@@ -50902,8 +51073,8 @@ var require_cache = __commonJS({
50902
51073
  function calcSimulatedDelay(contentLength, maxDelay) {
50903
51074
  return Math.min(Math.ceil(contentLength / CACHE_STREAM_CHUNK_SIZE) * CACHE_STREAM_DELAY, maxDelay);
50904
51075
  }
50905
- function setCachedResponse(messages, systemPromptContent, modelName, response, enableThinking = false) {
50906
- cacheLLM_1.llmCache.set(messages, systemPromptContent, modelName, response, enableThinking);
51076
+ function setCachedResponse(messages, systemPromptContent, modelName, response, enableThinking = false, temperature) {
51077
+ cacheLLM_1.llmCache.set(messages, systemPromptContent, modelName, response, enableThinking, temperature);
50907
51078
  }
50908
51079
  function getCacheSize() {
50909
51080
  return cacheLLM_1.llmCache.size();
@@ -64170,7 +64341,7 @@ var require_openai2 = __commonJS({
64170
64341
  }
64171
64342
  };
64172
64343
  }
64173
- async function queryOpenAI(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, emitChunkEvents) {
64344
+ async function queryOpenAI(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, temperature, emitChunkEvents) {
64174
64345
  const start = Date.now();
64175
64346
  let baseURL = modelProfile.baseURL || "https://api.openai.com/v1";
64176
64347
  const providerEndpoints = (0, providerEndpoint_1.getProviderEndpoints)(modelProfile.provider, baseURL);
@@ -64195,6 +64366,7 @@ var require_openai2 = __commonJS({
64195
64366
  stream: true,
64196
64367
  ...openaiTools && { tools: openaiTools },
64197
64368
  ...(0, adapter_1.useMaxCompletionTokens)(modelProfile.modelName) ? { max_completion_tokens: modelProfile.maxTokens || 8e3 } : { max_tokens: modelProfile.maxTokens || 8e3 },
64369
+ ...temperature !== void 0 && { temperature },
64198
64370
  // thinking 参数按 provider profile 统一构造(openai/openrouter/qwen/compat 等)
64199
64371
  ...(0, providerProfile_1.buildThinkingParams)(modelProfile, enableThinking)
64200
64372
  };
@@ -75404,7 +75576,7 @@ var require_anthropic = __commonJS({
75404
75576
  usage: usage2
75405
75577
  };
75406
75578
  }
75407
- async function queryAnthropic(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, emitChunkEvents) {
75579
+ async function queryAnthropic(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, temperature, emitChunkEvents) {
75408
75580
  const start = Date.now();
75409
75581
  const rawBaseURL = modelProfile.baseURL || "https://api.anthropic.com";
75410
75582
  const providerEndpoints = (0, providerEndpoint_1.getProviderEndpoints)(modelProfile.provider, rawBaseURL);
@@ -75425,7 +75597,7 @@ var require_anthropic = __commonJS({
75425
75597
  messages: anthropicMessages,
75426
75598
  system: systemPromptContent,
75427
75599
  max_tokens: modelProfile.maxTokens,
75428
- temperature: util_1.MAIN_QUERY_TEMPERATURE,
75600
+ ...temperature !== void 0 && { temperature },
75429
75601
  stream: true,
75430
75602
  ...anthropicTools && { tools: anthropicTools }
75431
75603
  };
@@ -75506,7 +75678,8 @@ var require_queryLLM = __commonJS({
75506
75678
  async function queryLLM(messages, systemPromptContent, signal, tools, modelPointer = "main", disableChunkEvents = false, suppressErrorEvent = false) {
75507
75679
  const modelProfile = (0, ModelManager_1.getModelManager)().getModel(modelPointer);
75508
75680
  if (!modelProfile) {
75509
- throw new Error(`\u89E3\u6790\u6A21\u578B\u5931\u8D25: ${modelPointer}`);
75681
+ const { id, overridden } = (0, ModelManager_1.getModelManager)().resolvePointer(modelPointer);
75682
+ throw new Error(id ? `\u89E3\u6790\u6A21\u578B\u5931\u8D25: ${modelPointer} \u2192 ${id} \u4E0D\u5728\u6A21\u578B\u914D\u7F6E\u4E2D${overridden ? "(\u4F1A\u8BDD\u7EA7\u8986\u76D6,\u6765\u81EA harness)" : ""}` : `\u89E3\u6790\u6A21\u578B\u5931\u8D25: ${modelPointer}`);
75510
75683
  }
75511
75684
  try {
75512
75685
  const coreConfig = (0, ConfManager_1.getConfManager)().getCoreConfig();
@@ -75514,30 +75687,31 @@ var require_queryLLM = __commonJS({
75514
75687
  const shouldStream = coreConfig?.stream !== false;
75515
75688
  const enableThinking = modelPointer !== "quick" && coreConfig?.thinking === true;
75516
75689
  const emitChunkEvents = !disableChunkEvents && shouldStream !== false;
75690
+ const adapt = modelProfile.adapt || (0, adapter_1.resolveAdapter)(modelProfile.provider, modelProfile.modelName);
75691
+ const temperature = (0, ModelManager_1.getModelManager)().resolveTemperature(modelPointer, modelProfile, { adapter: adapt, enableThinking });
75517
75692
  if (shouldUseCache) {
75518
- const cachedResponse = await (0, cache_1.tryGetCachedResponse)(messages, systemPromptContent, modelProfile.modelName, shouldStream, enableThinking, emitChunkEvents, signal);
75693
+ const cachedResponse = await (0, cache_1.tryGetCachedResponse)(messages, systemPromptContent, modelProfile.modelName, shouldStream, enableThinking, emitChunkEvents, signal, temperature);
75519
75694
  if (cachedResponse) {
75520
75695
  (0, logLLM_1.logLLMRequest)({ cached: true, model: modelProfile.modelName, messages });
75521
75696
  (0, logLLM_1.logLLMResponse)(cachedResponse);
75522
75697
  return cachedResponse;
75523
75698
  }
75524
75699
  }
75525
- const adapt = modelProfile.adapt || (0, adapter_1.resolveAdapter)(modelProfile.provider, modelProfile.modelName);
75526
75700
  let result2;
75527
75701
  switch (adapt) {
75528
75702
  case "anthropic":
75529
- result2 = await (0, anthropic_1.queryAnthropic)(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, emitChunkEvents);
75703
+ result2 = await (0, anthropic_1.queryAnthropic)(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, temperature, emitChunkEvents);
75530
75704
  break;
75531
75705
  case "openai":
75532
75706
  default:
75533
- result2 = await (0, openai_1.queryOpenAI)(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, emitChunkEvents);
75707
+ result2 = await (0, openai_1.queryOpenAI)(messages, systemPromptContent, tools, signal, modelProfile, enableThinking, temperature, emitChunkEvents);
75534
75708
  break;
75535
75709
  }
75536
75710
  (0, logLLM_1.logLLMResponse)(result2);
75537
75711
  if (shouldUseCache && !signal.aborted) {
75538
75712
  const hasContent = result2.message.content.some((block) => block.type === "text" && block.text.trim().length > 0 || block.type === "tool_use");
75539
75713
  if (hasContent) {
75540
- (0, cache_1.setCachedResponse)(messages, systemPromptContent, modelProfile.modelName, result2, enableThinking);
75714
+ (0, cache_1.setCachedResponse)(messages, systemPromptContent, modelProfile.modelName, result2, enableThinking, temperature);
75541
75715
  (0, log_1.logDebug)(`LLM\u54CD\u5E94\u5DF2\u7F13\u5B58\uFF0C\u5F53\u524D\u7F13\u5B58\u6761\u76EE\u6570: ${(0, cache_1.getCacheSize)()}`);
75542
75716
  }
75543
75717
  }
@@ -112415,6 +112589,12 @@ var require_SemaEngine = __commonJS({
112415
112589
  cfg.memoryFiles = partial2.memoryFiles ?? null;
112416
112590
  if ("personaFile" in partial2)
112417
112591
  cfg.personaFile = partial2.personaFile ?? null;
112592
+ if ("modelOverrides" in partial2)
112593
+ cfg.modelOverrides = partial2.modelOverrides ?? null;
112594
+ if ("temperatureOverrides" in partial2)
112595
+ cfg.temperatureOverrides = partial2.temperatureOverrides ?? null;
112596
+ if ("thinking" in partial2)
112597
+ cfg.thinking = partial2.thinking === true;
112418
112598
  }
112419
112599
  /**
112420
112600
  * 当前 session 的 coreConfig 只读快照(= initialConfig,含运行时 mutation 结果)。
@@ -113273,7 +113453,7 @@ var require_AtomixCore = __commonJS({
113273
113453
  exports2.AtomixCore = void 0;
113274
113454
  var SemaKernel_1 = require_SemaKernel();
113275
113455
  var ConfManager_1 = require_ConfManager();
113276
- var AtomixCore2 = class {
113456
+ var AtomixCore3 = class {
113277
113457
  constructor(config) {
113278
113458
  this.setWorkingDir = (newDir) => this.session.setWorkingDir(newDir);
113279
113459
  this.clearWorkingDir = () => this.session.clearWorkingDir();
@@ -113299,6 +113479,10 @@ var require_AtomixCore = __commonJS({
113299
113479
  this.switchModel = (ModelName) => this.kernel.models.switchCurrentModel(ModelName);
113300
113480
  this.applyTaskModel = (config2) => this.kernel.models.applyTaskModelConfig(config2);
113301
113481
  this.getModelData = () => this.kernel.models.getModelData();
113482
+ this.getModelNames = () => this.kernel.models.getModelNames();
113483
+ this.getModelPointers = () => this.kernel.models.getModelPointers();
113484
+ this.getModelProfiles = () => this.kernel.models.getModelProfiles();
113485
+ this.updateModel = (name, patch) => this.kernel.models.updateModelProfile(name, patch);
113302
113486
  this.updateCoreConfByKey = (key, value) => {
113303
113487
  if (key === "customRules") {
113304
113488
  this.session.updateAssemblyConfig({ customRules: value ?? "" });
@@ -113347,7 +113531,7 @@ var require_AtomixCore = __commonJS({
113347
113531
  return this.session.workbenchService;
113348
113532
  }
113349
113533
  };
113350
- exports2.AtomixCore = AtomixCore2;
113534
+ exports2.AtomixCore = AtomixCore3;
113351
113535
  }
113352
113536
  });
113353
113537
 
@@ -119922,7 +120106,7 @@ var require_dist4 = __commonJS({
119922
120106
  "../atomix-core/dist/index.js"(exports2) {
119923
120107
  "use strict";
119924
120108
  Object.defineProperty(exports2, "__esModule", { value: true });
119925
- exports2.fetchModels = exports2.testApiConnection = exports2.inferVision = exports2.modelHasVision = exports2.ImageLoadError = exports2.preprocessImage = exports2.imageBlockToPlaceholder = exports2.loadImagesAsBlocks = exports2.loadImageAsBlock = exports2.HOOK_EVENTS = exports2.executeHooks = exports2.HookManager = exports2.projectPathToDirName = exports2.getHistoryFilePath = exports2.getProjectHistoryDir = exports2.getHistoryDir = exports2.setModelConfigPathOverride = exports2.setLogLevel = exports2.getModelManager = exports2.SemaSession = exports2.SemaKernel = exports2.getAgentOwnedFilePaths = exports2.renderContextReminder = exports2.readContextSections = exports2.normalizeMemoryFiles = exports2.resolveContextFiles = exports2.isReadOnlyBashCommand = exports2.DEFAULT_PERMISSION_MODE = exports2.PERMISSION_MODES = exports2.assemblePromptSections = exports2.PROMPT_SECTION_CATALOG = exports2.AtomixCore = void 0;
120109
+ exports2.fetchModels = exports2.testApiConnection = exports2.inferVision = exports2.modelHasVision = exports2.ImageLoadError = exports2.preprocessImage = exports2.imageBlockToPlaceholder = exports2.loadImagesAsBlocks = exports2.loadImageAsBlock = exports2.HOOK_EVENTS = exports2.executeHooks = exports2.HookManager = exports2.projectPathToDirName = exports2.getHistoryFilePath = exports2.getProjectHistoryDir = exports2.getHistoryDir = exports2.setModelConfigPathOverride = exports2.setLogLevel = exports2.TEMPERATURE_MAX = exports2.TEMPERATURE_MIN = exports2.DEFAULT_ANTHROPIC_TEMPERATURE = exports2.isValidTemperature = exports2.openaiTemperatureCapability = exports2.modelTemperatureGatedByThinking = exports2.modelRejectsTemperature = exports2.modelForcesTemperatureOne = exports2.getModelManager = exports2.SemaSession = exports2.SemaKernel = exports2.getAgentOwnedFilePaths = exports2.renderContextReminder = exports2.readContextSections = exports2.normalizeMemoryFiles = exports2.resolveContextFiles = exports2.isReadOnlyBashCommand = exports2.DEFAULT_PERMISSION_MODE = exports2.PERMISSION_MODES = exports2.assemblePromptSections = exports2.PROMPT_SECTION_CATALOG = exports2.AtomixCore = void 0;
119926
120110
  var AtomixCore_1 = require_AtomixCore();
119927
120111
  Object.defineProperty(exports2, "AtomixCore", { enumerable: true, get: function() {
119928
120112
  return AtomixCore_1.AtomixCore;
@@ -119973,6 +120157,31 @@ var require_dist4 = __commonJS({
119973
120157
  Object.defineProperty(exports2, "getModelManager", { enumerable: true, get: function() {
119974
120158
  return ModelManager_1.getModelManager;
119975
120159
  } });
120160
+ var adapter_1 = require_adapter();
120161
+ Object.defineProperty(exports2, "modelForcesTemperatureOne", { enumerable: true, get: function() {
120162
+ return adapter_1.modelForcesTemperatureOne;
120163
+ } });
120164
+ Object.defineProperty(exports2, "modelRejectsTemperature", { enumerable: true, get: function() {
120165
+ return adapter_1.modelRejectsTemperature;
120166
+ } });
120167
+ Object.defineProperty(exports2, "modelTemperatureGatedByThinking", { enumerable: true, get: function() {
120168
+ return adapter_1.modelTemperatureGatedByThinking;
120169
+ } });
120170
+ Object.defineProperty(exports2, "openaiTemperatureCapability", { enumerable: true, get: function() {
120171
+ return adapter_1.openaiTemperatureCapability;
120172
+ } });
120173
+ Object.defineProperty(exports2, "isValidTemperature", { enumerable: true, get: function() {
120174
+ return adapter_1.isValidTemperature;
120175
+ } });
120176
+ Object.defineProperty(exports2, "DEFAULT_ANTHROPIC_TEMPERATURE", { enumerable: true, get: function() {
120177
+ return adapter_1.DEFAULT_ANTHROPIC_TEMPERATURE;
120178
+ } });
120179
+ Object.defineProperty(exports2, "TEMPERATURE_MIN", { enumerable: true, get: function() {
120180
+ return adapter_1.TEMPERATURE_MIN;
120181
+ } });
120182
+ Object.defineProperty(exports2, "TEMPERATURE_MAX", { enumerable: true, get: function() {
120183
+ return adapter_1.TEMPERATURE_MAX;
120184
+ } });
119976
120185
  var log_1 = require_log();
119977
120186
  Object.defineProperty(exports2, "setLogLevel", { enumerable: true, get: function() {
119978
120187
  return log_1.setLogLevel;
@@ -127599,6 +127808,113 @@ function getActivePersonaFile(core) {
127599
127808
  function getActiveHarnessName(core) {
127600
127809
  return runtimeOf(core)?.active?.name ?? BASE_HARNESS;
127601
127810
  }
127811
+ function getActiveHarnessDir(core) {
127812
+ return runtimeOf(core)?.active?.dirName ?? BASE_HARNESS;
127813
+ }
127814
+ function isHarnessActive(core) {
127815
+ return !!runtimeOf(core)?.active;
127816
+ }
127817
+ function harnessThinking(core) {
127818
+ return runtimeOf(core)?.active?.thinkingDeclared ?? null;
127819
+ }
127820
+ function appliedThinking(core) {
127821
+ return runtimeOf(core)?.activeThinking;
127822
+ }
127823
+ function thinkingStatusLine(core, current) {
127824
+ const on = (v) => v ? "on" : "off";
127825
+ const declared = harnessThinking(core);
127826
+ if (declared === null) return on(current);
127827
+ const dir = getActiveHarnessDir(core);
127828
+ return declared === current ? `${on(current)}(harness ${dir},\u4EC5 main;quick \u6052\u5173)` : `${on(current)}(\u4F1A\u8BDD\u4E34\u65F6\u5207\u6362;harness ${dir} \u58F0\u660E ${on(declared)},/harness use ${dir} \u91CD\u65B0\u5E94\u7528\u5373\u6062\u590D)`;
127829
+ }
127830
+ function harnessTemperatureOverride(core) {
127831
+ return runtimeOf(core)?.active?.temperatureOverrides ?? null;
127832
+ }
127833
+ function effectiveTemperatures(core) {
127834
+ const models = effectiveModels(core);
127835
+ const profiles = core.getModelProfiles();
127836
+ const over2 = harnessTemperatureOverride(core);
127837
+ const one = (slot) => {
127838
+ const prof = profiles.find((p) => p.name === models[slot]);
127839
+ const mn = prof?.modelName;
127840
+ if (mn && (0, import_atomix_core4.modelForcesTemperatureOne)(mn)) return { value: 1, from: "fixed" };
127841
+ if (mn && (0, import_atomix_core4.modelRejectsTemperature)(mn)) return { value: null, from: "unsupported" };
127842
+ const anthropic = prof?.adapt === "anthropic";
127843
+ const gatedByThinking = anthropic || (mn ? (0, import_atomix_core4.modelTemperatureGatedByThinking)(mn) : false);
127844
+ const notes = [];
127845
+ let from = "default";
127846
+ let raw;
127847
+ const o = over2?.[slot];
127848
+ if (o !== void 0) {
127849
+ if ((0, import_atomix_core4.isValidTemperature)(o)) {
127850
+ raw = o;
127851
+ from = "harness";
127852
+ } else notes.push(`harness \u503C ${JSON.stringify(o)} \u975E\u6CD5(\u987B 0\u20132),\u5DF2\u5FFD\u7565`);
127853
+ }
127854
+ if (raw === void 0 && prof?.temperature !== void 0) {
127855
+ if ((0, import_atomix_core4.isValidTemperature)(prof.temperature)) {
127856
+ raw = prof.temperature;
127857
+ from = "profile";
127858
+ } else notes.push(`profile \u503C ${JSON.stringify(prof.temperature)} \u975E\u6CD5(\u987B 0\u20132),\u5DF2\u5FFD\u7565`);
127859
+ }
127860
+ if (raw === void 0) {
127861
+ return { value: anthropic ? import_atomix_core4.DEFAULT_ANTHROPIC_TEMPERATURE : null, from: "default", ...gatedByThinking ? { gatedByThinking } : {}, ...notes.length ? { notes } : {} };
127862
+ }
127863
+ let value = raw;
127864
+ if (anthropic && value > 1) {
127865
+ value = 1;
127866
+ notes.push(`\u58F0\u660E ${raw} \u8D85 anthropic \u534F\u8BAE\u4E0A\u9650,\u5B9E\u9645\u6309 1 \u53D1`);
127867
+ }
127868
+ return { value, from, configured: raw, ...gatedByThinking ? { gatedByThinking } : {}, ...notes.length ? { notes } : {} };
127869
+ };
127870
+ return { main: one("main"), quick: one("quick") };
127871
+ }
127872
+ function formatTemperature(e, thinkingOn) {
127873
+ if (e.from === "fixed") return "1(\u6A21\u578B\u56FA\u5B9A)";
127874
+ if (e.from === "unsupported") return "\u4E0D\u652F\u6301";
127875
+ const notes = e.notes?.length ? ";" + e.notes.join(";") : "";
127876
+ const hint = e.gatedByThinking && thinkingOn === void 0 ? ";thinking \u5F00\u65F6\u4E0D\u53D1" : "";
127877
+ if (e.from === "default") {
127878
+ if (thinkingOn && e.gatedByThinking) return `\u4E0D\u53D1(thinking \u5F00;${e.value === null ? "\u5173\u65F6\u4E3A\u670D\u52A1\u7AEF\u9ED8\u8BA4" : `\u5173\u65F6\u4E3A\u9ED8\u8BA4 ${e.value}`}${notes})`;
127879
+ return `\u9ED8\u8BA4(${e.value === null ? "\u670D\u52A1\u7AEF" : e.value}${notes}${hint})`;
127880
+ }
127881
+ const cfg = `${e.configured ?? e.value}(${e.from})`;
127882
+ if (thinkingOn && e.gatedByThinking) return `\u4E0D\u53D1(thinking \u5F00;\u914D\u7F6E ${cfg}${notes})`;
127883
+ return `${e.value}(${e.from}${notes}${hint})`;
127884
+ }
127885
+ function temperatureStatusLine(core, thinkingOn) {
127886
+ const t = effectiveTemperatures(core);
127887
+ return `main=${formatTemperature(t.main, thinkingOn)} quick=${formatTemperature(t.quick, false)}`;
127888
+ }
127889
+ function harnessModelOverride(core) {
127890
+ return runtimeOf(core)?.active?.modelOverrides ?? null;
127891
+ }
127892
+ function harnessModelFallback(core) {
127893
+ return runtimeOf(core)?.active?.modelFallback ?? null;
127894
+ }
127895
+ function harnessModelDeclared(core) {
127896
+ return runtimeOf(core)?.active?.modelDeclared ?? null;
127897
+ }
127898
+ function effectiveModels(core) {
127899
+ const base = core.getModelPointers();
127900
+ const over2 = harnessModelOverride(core);
127901
+ const fb = harnessModelFallback(core);
127902
+ const pick2 = (slot) => over2?.[slot] ? [over2[slot], "harness"] : [base[slot], fb?.[slot] ? "fallback" : "base"];
127903
+ const [main, mainFrom] = pick2("main");
127904
+ const [quick, quickFrom] = pick2("quick");
127905
+ return { main, quick, mainFrom, quickFrom, ...fb ? { fallback: fb } : {} };
127906
+ }
127907
+ function modelStatusLine(core) {
127908
+ const m = effectiveModels(core);
127909
+ if (m.mainFrom === "base" && m.quickFrom === "base") return `main=${m.main || "-"} quick=${m.quick || "-"}`;
127910
+ const part = (slot) => {
127911
+ const v = m[slot] || "-";
127912
+ const from = slot === "main" ? m.mainFrom : m.quickFrom;
127913
+ if (from === "fallback") return `${slot}=${v} (base;harness \u58F0\u660E ${m.fallback?.[slot]} \u4E0D\u5B58\u5728,\u5DF2\u56DE\u843D)`;
127914
+ return `${slot}=${v} (${from})`;
127915
+ };
127916
+ return `${m.fallback ? "\u26A0 " : ""}${part("main")} ${part("quick")}`;
127917
+ }
127602
127918
  function isHarnessOverridden(core) {
127603
127919
  return runtimeOf(core)?.overridden ?? false;
127604
127920
  }
@@ -127784,6 +128100,67 @@ function loadHarnessDoc(name) {
127784
128100
  };
127785
128101
  const memory = parseToggle(raw.memory, "memory");
127786
128102
  const persona = parseToggle(raw.persona, "persona");
128103
+ const parseModel = (v) => {
128104
+ if (v === void 0 || v === null) return null;
128105
+ if (typeof v === "string") {
128106
+ const id = v.trim();
128107
+ if (id) return { main: id, quick: id };
128108
+ toggleWarnings.push("model \u4E3A\u7A7A\u5B57\u7B26\u4E32,\u5FFD\u7565(\u89C6\u4E3A\u672A\u58F0\u660E,\u8DDF\u968F base)");
128109
+ return null;
128110
+ }
128111
+ if (typeof v === "object" && !Array.isArray(v)) {
128112
+ const o = v;
128113
+ const out = {};
128114
+ for (const slot of MODEL_SLOTS) {
128115
+ const x = o[slot];
128116
+ if (x === void 0 || x === null) continue;
128117
+ if (typeof x === "string" && x.trim()) out[slot] = x.trim();
128118
+ else toggleWarnings.push(`model.${slot} \u987B\u4E3A\u6A21\u578B\u6807\u8BC6\u5B57\u7B26\u4E32(modelName[provider]),\u5FFD\u7565\u975E\u6CD5\u503C ${JSON.stringify(x)}`);
128119
+ }
128120
+ for (const k of Object.keys(o)) if (!MODEL_SLOTS.includes(k)) toggleWarnings.push(`model \u672A\u77E5\u69FD\u4F4D ${k}(\u53EA\u8BA4 main / quick),\u5FFD\u7565`);
128121
+ if (!out.main && !out.quick) {
128122
+ toggleWarnings.push("model \u672A\u58F0\u660E\u4EFB\u4F55\u6709\u6548\u69FD\u4F4D,\u89C6\u4E3A\u672A\u58F0\u660E(\u8DDF\u968F base)");
128123
+ return null;
128124
+ }
128125
+ return out;
128126
+ }
128127
+ toggleWarnings.push(`model \u53EA\u8BA4\u5B57\u7B26\u4E32\u6216 { main, quick },\u5FFD\u7565\u975E\u6CD5\u503C ${JSON.stringify(v)}`);
128128
+ return null;
128129
+ };
128130
+ const model = parseModel(raw.model);
128131
+ const thinkingToggle = parseToggle(raw.thinking, "thinking");
128132
+ const thinking = thinkingToggle === null ? null : thinkingToggle === "on";
128133
+ const parseTemperature = (v) => {
128134
+ if (v === void 0 || v === null) return null;
128135
+ const num = (x, label) => {
128136
+ if ((0, import_atomix_core4.isValidTemperature)(x)) return x;
128137
+ toggleWarnings.push(`${label} \u987B\u4E3A 0\u20132 \u7684\u6570\u5B57,\u5FFD\u7565\u975E\u6CD5\u503C ${JSON.stringify(x)}`);
128138
+ return void 0;
128139
+ };
128140
+ if (typeof v === "number") {
128141
+ const t2 = num(v, "temperature");
128142
+ return t2 === void 0 ? null : { main: t2 };
128143
+ }
128144
+ if (typeof v === "object" && !Array.isArray(v)) {
128145
+ const o = v;
128146
+ const out = {};
128147
+ for (const slot of MODEL_SLOTS) {
128148
+ const x = o[slot];
128149
+ if (x === void 0 || x === null) continue;
128150
+ const t2 = num(x, `temperature.${slot}`);
128151
+ if (t2 !== void 0) out[slot] = t2;
128152
+ }
128153
+ for (const k of Object.keys(o)) if (!MODEL_SLOTS.includes(k)) toggleWarnings.push(`temperature \u672A\u77E5\u69FD\u4F4D ${k}(\u53EA\u8BA4 main / quick),\u5FFD\u7565`);
128154
+ if (out.main === void 0 && out.quick === void 0) {
128155
+ toggleWarnings.push("temperature \u672A\u58F0\u660E\u4EFB\u4F55\u6709\u6548\u69FD\u4F4D,\u89C6\u4E3A\u672A\u58F0\u660E");
128156
+ return null;
128157
+ }
128158
+ return out;
128159
+ }
128160
+ toggleWarnings.push(`temperature \u53EA\u8BA4\u6570\u5B57\u6216 { main, quick },\u5FFD\u7565\u975E\u6CD5\u503C ${JSON.stringify(v)}`);
128161
+ return null;
128162
+ };
128163
+ const temperature = parseTemperature(raw.temperature);
127787
128164
  return {
127788
128165
  name: typeof raw.name === "string" && raw.name ? raw.name : name,
127789
128166
  description: typeof raw.description === "string" ? raw.description : void 0,
@@ -127804,6 +128181,9 @@ function loadHarnessDoc(name) {
127804
128181
  memory,
127805
128182
  persona,
127806
128183
  soulPath,
128184
+ model,
128185
+ thinking,
128186
+ temperature,
127807
128187
  toggleWarnings,
127808
128188
  dir
127809
128189
  };
@@ -127819,6 +128199,14 @@ function resolveBase(ctx) {
127819
128199
  memoryFiles: ctx.baseline.memoryFiles,
127820
128200
  personaFile: ctx.baseline.personaFile,
127821
128201
  warnings: [],
128202
+ dirName: BASE_HARNESS,
128203
+ modelOverrides: null,
128204
+ modelDeclared: null,
128205
+ modelFallback: null,
128206
+ thinkingDeclared: null,
128207
+ temperatureOverrides: null,
128208
+ temperatureDeclared: null,
128209
+ thinking: ctx.baseline.thinking,
127822
128210
  skillsSpec: null,
127823
128211
  agentsSpec: null,
127824
128212
  skillsDisabled: /* @__PURE__ */ new Set(),
@@ -127869,8 +128257,49 @@ function resolveHarness(doc, ctx) {
127869
128257
  if (doc.persona === "on") warnings.push("persona: on \u65E0\u6548:\u672C harness \u672A\u5E26\u4E13\u5C5E SOUL.md(\u4E25\u683C\u9694\u79BB,\u4E0D\u501F base \u4EBA\u8BBE;\u653E\u4E00\u4EFD SOUL.md \u8FDB harness \u76EE\u5F55\u5373\u751F\u6548)");
127870
128258
  personaFile = null;
127871
128259
  }
128260
+ const dirName = path3.basename(doc.dir);
128261
+ const modelOverrides = {};
128262
+ const modelFallback = {};
128263
+ if (doc.model) {
128264
+ for (const slot of MODEL_SLOTS) {
128265
+ const want = doc.model[slot];
128266
+ if (!want) continue;
128267
+ if (ctx.modelNames.includes(want)) modelOverrides[slot] = want;
128268
+ else {
128269
+ modelFallback[slot] = want;
128270
+ warnings.push(`\u6A21\u578B\u56DE\u843D:harness.yaml \u58F0\u660E ${slot}=${want},model.conf \u4E2D\u4E0D\u5B58\u5728,\u5F53\u524D ${slot} \u4F7F\u7528 base \u7684 ${ctx.baseModels[slot] || "-"}(/model add \u6DFB\u52A0\u540E /harness use ${dirName} \u91CD\u65B0\u5E94\u7528)`);
128271
+ }
128272
+ }
128273
+ }
128274
+ const temperatureOverrides = {};
128275
+ if (doc.temperature) {
128276
+ for (const slot of MODEL_SLOTS) {
128277
+ const t = doc.temperature[slot];
128278
+ if (t === void 0) continue;
128279
+ const effModel = modelOverrides[slot] ?? ctx.baseModels[slot];
128280
+ const mn = ctx.modelProfiles?.find((p) => p.name === effModel)?.modelName;
128281
+ if (mn && (0, import_atomix_core4.modelForcesTemperatureOne)(mn)) {
128282
+ warnings.push(`\u6E29\u5EA6\u5FFD\u7565:harness.yaml \u58F0\u660E ${slot} temperature=${t},\u4F46\u6A21\u578B ${effModel} \u53EA\u63A5\u53D7\u9ED8\u8BA4\u6E29\u5EA6 1`);
128283
+ continue;
128284
+ }
128285
+ if (mn && (0, import_atomix_core4.modelRejectsTemperature)(mn)) {
128286
+ warnings.push(`\u6E29\u5EA6\u5FFD\u7565:harness.yaml \u58F0\u660E ${slot} temperature=${t},\u4F46\u6A21\u578B ${effModel} \u4E0D\u652F\u6301 temperature \u53C2\u6570`);
128287
+ continue;
128288
+ }
128289
+ temperatureOverrides[slot] = t;
128290
+ }
128291
+ }
127872
128292
  return {
127873
128293
  name: doc.name,
128294
+ dirName,
128295
+ temperatureOverrides: Object.keys(temperatureOverrides).length ? temperatureOverrides : null,
128296
+ temperatureDeclared: doc.temperature,
128297
+ modelOverrides: Object.keys(modelOverrides).length ? modelOverrides : null,
128298
+ modelDeclared: doc.model,
128299
+ modelFallback: Object.keys(modelFallback).length ? modelFallback : null,
128300
+ // thinking:声明即下发;未声明跟随基线(基线未知则不下发该键,与 memoryFiles 同规则)
128301
+ thinkingDeclared: doc.thinking,
128302
+ thinking: doc.thinking ?? ctx.baseline.thinking,
127874
128303
  useTools,
127875
128304
  deferBuiltinTools: doc.tools.defer.length ? doc.tools.defer : ctx.baseline.deferBuiltinTools ?? [],
127876
128305
  pinnedTools: doc.tools.pin,
@@ -127895,10 +128324,13 @@ function buildContext(core) {
127895
128324
  // 缓存为空只在启动初始化时(此刻尚未过滤,直读即全集)
127896
128325
  allToolNames: core.getToolInfos().map((t) => t.name),
127897
128326
  allSkillNames: rt.fullSkillNames ?? core.getSkillsInfo({ includeDisabled: true }).map((s) => s.name),
127898
- allAgentNames: rt.fullAgentNames ?? core.getAgentsInfo().map((a) => a.name)
128327
+ allAgentNames: rt.fullAgentNames ?? core.getAgentsInfo().map((a) => a.name),
128328
+ modelNames: core.getModelNames(),
128329
+ baseModels: core.getModelPointers(),
128330
+ modelProfiles: core.getModelProfiles()
127899
128331
  };
127900
128332
  }
127901
- function applyAssembly(core, rt, r) {
128333
+ function applyAssembly(core, rt, r, opts = {}) {
127902
128334
  core.updateAssemblyConfig({
127903
128335
  useTools: r.useTools,
127904
128336
  deferBuiltinTools: r.deferBuiltinTools,
@@ -127908,11 +128340,18 @@ function applyAssembly(core, rt, r) {
127908
128340
  // null = 回默认组装(base 清场)
127909
128341
  // 基线未知(宿主没给快照)时不下发该键:传 undefined 会被 core 当 null 落,把供给层开着的注入误关
127910
128342
  ...r.memoryFiles !== void 0 ? { memoryFiles: r.memoryFiles } : {},
127911
- ...r.personaFile !== void 0 ? { personaFile: r.personaFile } : {}
128343
+ ...r.personaFile !== void 0 ? { personaFile: r.personaFile } : {},
128344
+ modelOverrides: r.modelOverrides,
128345
+ // null = 回 model.conf 指针(base 清场)
128346
+ temperatureOverrides: r.temperatureOverrides,
128347
+ // null = 回 profile / 协议默认(base 清场)
128348
+ ...!opts.preserveThinking && r.thinking !== void 0 ? { thinking: r.thinking } : {}
128349
+ // 声明 ?? 基线;只在 use/reset/启动 下发,不做热切换
127912
128350
  });
127913
128351
  rt.activeMemoryFiles = r.memoryFiles;
127914
128352
  rt.activePersonaFile = r.personaFile;
127915
- rt.active = r.name === BASE_HARNESS ? null : r;
128353
+ if (!opts.preserveThinking) rt.activeThinking = r.thinking;
128354
+ rt.active = r.dirName === BASE_HARNESS ? null : r;
127916
128355
  }
127917
128356
  function initHarness(core, cwd, base, opts = {}) {
127918
128357
  const rt = {
@@ -127921,10 +128360,12 @@ function initHarness(core, cwd, base, opts = {}) {
127921
128360
  deferBuiltinTools: base.deferBuiltinTools?.slice(),
127922
128361
  memoryFiles: base.memoryFiles,
127923
128362
  personaFile: base.personaFile,
127924
- potentialMemoryFiles: base.potentialMemoryFiles
128363
+ potentialMemoryFiles: base.potentialMemoryFiles,
128364
+ thinking: base.thinking
127925
128365
  },
127926
128366
  activeMemoryFiles: base.memoryFiles,
127927
128367
  activePersonaFile: base.personaFile,
128368
+ activeThinking: base.thinking,
127928
128369
  projectDir: cwd,
127929
128370
  active: null,
127930
128371
  overridden: opts.harness !== void 0,
@@ -127973,6 +128414,63 @@ async function switchTo(core, name) {
127973
128414
  ${h}`).join("");
127974
128415
  return (name === BASE_HARNESS ? "\u5DF2\u56DE\u5230 base(\u9ED8\u8BA4\u88C5\u914D)" : `\u5DF2\u5207\u6362 harness:${r.name}(\u4EC5\u5F53\u524D\u9879\u76EE\u751F\u6548)`) + hintText + warn;
127975
128416
  }
128417
+ function reapply(core, rt) {
128418
+ const r = resolveHarness(loadHarnessDoc(rt.active.dirName), buildContext(core));
128419
+ applyAssembly(core, rt, r, { preserveThinking: true });
128420
+ return r;
128421
+ }
128422
+ function setActiveHarnessModel(core, slot, name) {
128423
+ const rt = requireRuntime(core);
128424
+ if (!rt.active) throw new Error("\u5F53\u524D\u4E3A base,\u6A21\u578B\u6307\u9488\u76F4\u63A5\u7531 model.conf \u7BA1\u7406");
128425
+ if (!core.getModelNames().includes(name)) throw new Error(`\u6A21\u578B\u4E0D\u5B58\u5728: ${name}(/model list \u67E5\u770B,/model add \u6DFB\u52A0)`);
128426
+ const dirName = rt.active.dirName;
128427
+ const declared = { ...rt.active.modelDeclared ?? {} };
128428
+ declared[slot] = name;
128429
+ const value = declared.main && declared.quick && declared.main === declared.quick ? declared.main : declared;
128430
+ const yamlPath = path3.join(libraryDir(), dirName, "harness.yaml");
128431
+ const ydoc = import_yaml.default.parseDocument(fs3.readFileSync(yamlPath, "utf8"));
128432
+ ydoc.set("model", typeof value === "string" ? value : ydoc.createNode(value));
128433
+ fs3.writeFileSync(yamlPath, ydoc.toString());
128434
+ const r = reapply(core, rt);
128435
+ const warn = r.warnings.length ? "\n \u26A0 " + r.warnings.join("\n \u26A0 ") : "";
128436
+ return `harness ${dirName} \u7684 ${slot} \u2192 ${name}(\u5DF2\u5199\u5165 harness.yaml,base \u672A\u53D8)` + warn;
128437
+ }
128438
+ function setActiveHarnessTemperature(core, slot, value) {
128439
+ const rt = requireRuntime(core);
128440
+ if (!rt.active) throw new Error("\u5F53\u524D\u4E3A base,\u6E29\u5EA6\u76F4\u63A5\u7531 model.conf \u7684 profile \u7BA1\u7406(/model temp <\u6A21\u578B\u540D> <\u503C|default>)");
128441
+ if (value !== null) {
128442
+ if (!(0, import_atomix_core4.isValidTemperature)(value)) throw new Error(`temperature \u987B\u4E3A 0\u20132 \u7684\u6570\u5B57,\u6536\u5230 ${JSON.stringify(value)}`);
128443
+ const effModel = effectiveModels(core)[slot];
128444
+ const mn = core.getModelProfiles().find((p) => p.name === effModel)?.modelName;
128445
+ if (mn && (0, import_atomix_core4.modelForcesTemperatureOne)(mn)) throw new Error(`\u6A21\u578B ${effModel} \u53EA\u63A5\u53D7\u9ED8\u8BA4\u6E29\u5EA6 1,\u4E0D\u80FD\u8BBE\u7F6E temperature`);
128446
+ if (mn && (0, import_atomix_core4.modelRejectsTemperature)(mn)) throw new Error(`\u6A21\u578B ${effModel} \u4E0D\u652F\u6301 temperature \u53C2\u6570(\u63A8\u7406\u6A21\u578B),\u4E0D\u80FD\u8BBE\u7F6E`);
128447
+ }
128448
+ const dirName = rt.active.dirName;
128449
+ const declared = { ...rt.active.temperatureDeclared ?? {} };
128450
+ if (value === null) delete declared[slot];
128451
+ else declared[slot] = value;
128452
+ const yamlPath = path3.join(libraryDir(), dirName, "harness.yaml");
128453
+ const ydoc = import_yaml.default.parseDocument(fs3.readFileSync(yamlPath, "utf8"));
128454
+ if (declared.main === void 0 && declared.quick === void 0) ydoc.delete("temperature");
128455
+ else if (declared.quick === void 0) ydoc.set("temperature", declared.main);
128456
+ else ydoc.set("temperature", ydoc.createNode(declared));
128457
+ fs3.writeFileSync(yamlPath, ydoc.toString());
128458
+ const r = reapply(core, rt);
128459
+ const warn = r.warnings.length ? "\n \u26A0 " + r.warnings.join("\n \u26A0 ") : "";
128460
+ return `harness ${dirName} \u7684 ${slot} temperature \u2192 ${value === null ? "\u9ED8\u8BA4(\u5DF2\u6E05\u9664\u58F0\u660E)" : value}(\u5DF2\u5199\u5165 harness.yaml,model.conf \u672A\u53D8)` + warn;
128461
+ }
128462
+ function harnessesReferencingModel(name) {
128463
+ const out = [];
128464
+ for (const n of listHarnesses()) {
128465
+ if (n === BASE_HARNESS) continue;
128466
+ try {
128467
+ const m = loadHarnessDoc(n).model;
128468
+ if (m && (m.main === name || m.quick === name)) out.push(n);
128469
+ } catch {
128470
+ }
128471
+ }
128472
+ return out;
128473
+ }
127976
128474
  function summarize(r, ctx) {
127977
128475
  const lines = [];
127978
128476
  const base = resolveBase(ctx);
@@ -128002,6 +128500,23 @@ function summarize(r, ctx) {
128002
128500
  if (po === "off") lines.push("\u4EBA\u8BBE \u5173(\u672C harness \u65E0\u4EBA\u8BBE;base \u5F00\u7740,\u5207\u8D70\u5373\u6062\u590D)");
128003
128501
  else if (po === "swap") lines.push("\u4EBA\u8BBE \u4E13\u5C5E(harness SOUL.md;\u5207\u8D70\u5373\u56DE base)");
128004
128502
  else if (po === "on") lines.push("\u4EBA\u8BBE \u4E13\u5C5E(harness SOUL.md;base \u5173\u7740,\u5207\u8D70\u5373\u5173)");
128503
+ if (r.modelDeclared) {
128504
+ const parts = MODEL_SLOTS.map((slot) => {
128505
+ const d = r.modelDeclared[slot];
128506
+ if (!d) return `${slot}=${ctx.baseModels[slot] || "-"}(base)`;
128507
+ return r.modelFallback?.[slot] ? `${slot}=${ctx.baseModels[slot] || "-"}(base;\u58F0\u660E ${d} \u4E0D\u5B58\u5728,\u5DF2\u56DE\u843D)` : `${slot}=${d}`;
128508
+ });
128509
+ lines.push(`${r.modelFallback ? "\u26A0 " : ""}\u6A21\u578B ${parts.join(" ")}`);
128510
+ }
128511
+ if (r.thinkingDeclared !== null) lines.push(`\u601D\u8003 ${r.thinkingDeclared ? "\u5F00" : "\u5173"}(harness thinking: ${r.thinkingDeclared ? "on" : "off"};\u4EC5 main,quick \u6052\u5173;\u5207\u8D70\u5373\u56DE base)`);
128512
+ if (r.temperatureDeclared) {
128513
+ const parts = MODEL_SLOTS.map((slot) => {
128514
+ const d = r.temperatureDeclared[slot];
128515
+ if (d === void 0) return `${slot}=\u8DDF\u968F(profile / \u534F\u8BAE\u9ED8\u8BA4)`;
128516
+ return r.temperatureOverrides?.[slot] === void 0 ? `${slot}=${d}(\u5DF2\u5FFD\u7565,\u89C1\u544A\u8B66)` : `${slot}=${d}`;
128517
+ });
128518
+ lines.push(`\u6E29\u5EA6 ${parts.join(" ")}(harness \u58F0\u660E;\u5207\u8D70\u5373\u56DE profile / \u9ED8\u8BA4)`);
128519
+ }
128005
128520
  if (r.warnings.length) lines.push(...r.warnings.map((w) => `\u26A0 ${w}`));
128006
128521
  return lines.join("\n ");
128007
128522
  }
@@ -128012,7 +128527,7 @@ async function harnessCommand(core, args) {
128012
128527
  switch (sub) {
128013
128528
  case void 0:
128014
128529
  case "list": {
128015
- const cur = getActiveHarnessName(core);
128530
+ const cur = getActiveHarnessDir(core);
128016
128531
  const rt = runtimeOf(core);
128017
128532
  const lines = names.map((n) => `${n === cur ? "\u25CF" : "\u25CB"} ${n}${n === BASE_HARNESS ? "(\u9ED8\u8BA4\u88C5\u914D)" : ""}`);
128018
128533
  if (sub === void 0 && rt?.active) {
@@ -128044,7 +128559,7 @@ async function harnessCommand(core, args) {
128044
128559
  try {
128045
128560
  const ctx = buildContext(core);
128046
128561
  const r = resolveHarness(loadHarnessDoc(arg), ctx);
128047
- return `${r.name}${arg === getActiveHarnessName(core) ? "(\u5F53\u524D)" : ""}
128562
+ return `${r.name}${arg === getActiveHarnessDir(core) ? "(\u5F53\u524D)" : ""}
128048
128563
  ${summarize(r, ctx)}`;
128049
128564
  } catch (e) {
128050
128565
  return `\u8BFB\u53D6\u5931\u8D25:${e instanceof Error ? e.message : e}`;
@@ -128054,7 +128569,7 @@ async function harnessCommand(core, args) {
128054
128569
  return `\u672A\u77E5\u5B50\u547D\u4EE4:${sub}(\u53EF\u7528:list / use / show / diff / reset)`;
128055
128570
  }
128056
128571
  }
128057
- var fs3, path3, import_yaml, import_atomix_core3, BASE_HARNESS, runtimes;
128572
+ var fs3, path3, import_yaml, import_atomix_core3, import_atomix_core4, MODEL_SLOTS, BASE_HARNESS, runtimes;
128058
128573
  var init_harness = __esm({
128059
128574
  "src/harness.ts"() {
128060
128575
  "use strict";
@@ -128062,7 +128577,9 @@ var init_harness = __esm({
128062
128577
  path3 = __toESM(require("path"));
128063
128578
  import_yaml = __toESM(require_dist5());
128064
128579
  import_atomix_core3 = __toESM(require_dist4());
128580
+ import_atomix_core4 = __toESM(require_dist4());
128065
128581
  init_paths();
128582
+ MODEL_SLOTS = ["main", "quick"];
128066
128583
  BASE_HARNESS = "base";
128067
128584
  runtimes = /* @__PURE__ */ new WeakMap();
128068
128585
  }
@@ -128071,7 +128588,7 @@ var init_harness = __esm({
128071
128588
  // src/memoryPaths.ts
128072
128589
  function getMemoryPaths(cwd) {
128073
128590
  const root3 = realpathOrSelf(getAtomixRoot());
128074
- const slug = (0, import_atomix_core4.projectPathToDirName)(cwd);
128591
+ const slug = (0, import_atomix_core5.projectPathToDirName)(cwd);
128075
128592
  const projectDir = path4.join(root3, "projects", slug);
128076
128593
  return {
128077
128594
  root: root3,
@@ -128089,13 +128606,13 @@ function realpathOrSelf(p) {
128089
128606
  return p;
128090
128607
  }
128091
128608
  }
128092
- var fs4, path4, import_atomix_core4;
128609
+ var fs4, path4, import_atomix_core5;
128093
128610
  var init_memoryPaths = __esm({
128094
128611
  "src/memoryPaths.ts"() {
128095
128612
  "use strict";
128096
128613
  fs4 = __toESM(require("fs"));
128097
128614
  path4 = __toESM(require("path"));
128098
- import_atomix_core4 = __toESM(require_dist4());
128615
+ import_atomix_core5 = __toESM(require_dist4());
128099
128616
  init_paths();
128100
128617
  }
128101
128618
  });
@@ -129348,16 +129865,16 @@ function loadHooks(cwd) {
129348
129865
  hookEnv: vars
129349
129866
  };
129350
129867
  }
129351
- var fs9, path9, import_atomix_core5, VALID_EVENTS;
129868
+ var fs9, path9, import_atomix_core6, VALID_EVENTS;
129352
129869
  var init_hooksLoader = __esm({
129353
129870
  "src/hooksLoader.ts"() {
129354
129871
  "use strict";
129355
129872
  fs9 = __toESM(require("fs"));
129356
129873
  path9 = __toESM(require("path"));
129357
- import_atomix_core5 = __toESM(require_dist4());
129874
+ import_atomix_core6 = __toESM(require_dist4());
129358
129875
  init_paths();
129359
129876
  init_marketplace();
129360
- VALID_EVENTS = new Set(import_atomix_core5.HOOK_EVENTS);
129877
+ VALID_EVENTS = new Set(import_atomix_core6.HOOK_EVENTS);
129361
129878
  }
129362
129879
  });
129363
129880
 
@@ -129401,7 +129918,7 @@ function prepareProcess(cwd) {
129401
129918
  }
129402
129919
  function createSessionCore(opts) {
129403
129920
  const interactive = opts.interactive ?? false;
129404
- const permissionMode = opts.permissionMode ?? (interactive ? import_atomix_core6.DEFAULT_PERMISSION_MODE : "free-style");
129921
+ const permissionMode = opts.permissionMode ?? (interactive ? import_atomix_core7.DEFAULT_PERMISSION_MODE : "free-style");
129405
129922
  const notes = [];
129406
129923
  const prepNote = prepareProcess(opts.cwd);
129407
129924
  if (prepNote) notes.push(prepNote);
@@ -129409,7 +129926,7 @@ function createSessionCore(opts) {
129409
129926
  const contextFiles = buildContextFilesConfig(opts.cwd, appConfig);
129410
129927
  const hookCfg = opts.hooks ?? interactive ? loadHooks(opts.cwd) : {};
129411
129928
  const dirs = { skills: buildSkillsExtraDirs(), agents: buildAgentsExtraDirs(), commands: buildCommandsExtraDirs() };
129412
- const core = new import_atomix_core6.AtomixCore({
129929
+ const core = new import_atomix_core7.AtomixCore({
129413
129930
  workingDir: opts.cwd,
129414
129931
  logLevel: opts.logLevel ?? atomixLogLevel(),
129415
129932
  stream: opts.stream ?? interactive,
@@ -129433,7 +129950,9 @@ function createSessionCore(opts) {
129433
129950
  deferBuiltinTools: ATOMIX_DEFER_TOOLS,
129434
129951
  memoryFiles: contextFiles.memoryFiles,
129435
129952
  personaFile: contextFiles.personaFile,
129436
- potentialMemoryFiles: potential.memoryFiles
129953
+ potentialMemoryFiles: potential.memoryFiles,
129954
+ thinking: false
129955
+ // cli 构造 core 时 thinking 关;harness 未声明即回到这里
129437
129956
  };
129438
129957
  return { [SESSION_HANDLE_BRAND]: true, core, cwd: opts.cwd, interactive, permissionMode, appConfig, contextFiles, baseline, notes };
129439
129958
  }
@@ -129514,11 +130033,11 @@ function attachHeadlessResponder(core) {
129514
130033
  }
129515
130034
  };
129516
130035
  }
129517
- var import_atomix_core6, MAIN, DEFAULT_SYSTEM_PROMPT, DEFAULT_SEND_TIMEOUT_MS, SESSION_ID_PATTERN, preparedCwd, DISPOSED_ERROR, SessionImpl;
130036
+ var import_atomix_core7, MAIN, DEFAULT_SYSTEM_PROMPT, DEFAULT_SEND_TIMEOUT_MS, SESSION_ID_PATTERN, preparedCwd, DISPOSED_ERROR, SessionImpl;
129518
130037
  var init_session = __esm({
129519
130038
  "src/session.ts"() {
129520
130039
  "use strict";
129521
- import_atomix_core6 = __toESM(require_dist4());
130040
+ import_atomix_core7 = __toESM(require_dist4());
129522
130041
  init_sessionTypes();
129523
130042
  init_tools();
129524
130043
  init_skills();
@@ -129561,6 +130080,16 @@ var init_session = __esm({
129561
130080
  get harness() {
129562
130081
  return getActiveHarnessName(this.core);
129563
130082
  }
130083
+ get model() {
130084
+ const m = effectiveModels(this.core);
130085
+ const t = effectiveTemperatures(this.core);
130086
+ const temperature = {};
130087
+ for (const slot of ["main", "quick"]) {
130088
+ const e = t[slot];
130089
+ if ((e.from === "harness" || e.from === "profile") && e.value !== null) temperature[slot] = e.value;
130090
+ }
130091
+ return { main: m.main, quick: m.quick, ...m.fallback ? { fallback: m.fallback } : {}, ...Object.keys(temperature).length ? { temperature } : {} };
130092
+ }
129564
130093
  on(event, listener) {
129565
130094
  this.core.on(event, listener);
129566
130095
  }
@@ -129685,6 +130214,9 @@ var init_streamEvents = __esm({
129685
130214
  });
129686
130215
 
129687
130216
  // src/ui.ts
130217
+ function paintLines(text, base = gray) {
130218
+ return text.split("\n").map((line) => line.trimStart().startsWith("\u26A0") ? yellow(line) : base(line)).join("\n");
130219
+ }
129688
130220
  function truncate2(s, n) {
129689
130221
  if (s.length <= n) return s;
129690
130222
  return s.slice(0, n) + gray(` \u2026(+${s.length - n} chars)`);
@@ -129768,6 +130300,7 @@ function buildResultRecord(session, result2) {
129768
130300
  sessionId: session.sessionId,
129769
130301
  harness: session.harness,
129770
130302
  permissionMode: session.permissionMode,
130303
+ ...session.model ? { model: session.model } : {},
129771
130304
  notes: session.notes,
129772
130305
  text: result2.text,
129773
130306
  texts: result2.texts,
@@ -129893,7 +130426,7 @@ function readMessages(file) {
129893
130426
  }
129894
130427
  }
129895
130428
  function listSessions(cwd) {
129896
- const dir = (0, import_atomix_core7.getProjectHistoryDir)(cwd);
130429
+ const dir = (0, import_atomix_core8.getProjectHistoryDir)(cwd);
129897
130430
  if (!fs10.existsSync(dir)) return [];
129898
130431
  const entries = [];
129899
130432
  for (const f of fs10.readdirSync(dir)) {
@@ -129925,13 +130458,13 @@ function loadReplay(cwd, sessionId, maxItems = 20) {
129925
130458
  }
129926
130459
  return out.slice(-maxItems);
129927
130460
  }
129928
- var fs10, path10, import_atomix_core7;
130461
+ var fs10, path10, import_atomix_core8;
129929
130462
  var init_resume = __esm({
129930
130463
  "src/resume.ts"() {
129931
130464
  "use strict";
129932
130465
  fs10 = __toESM(require("fs"));
129933
130466
  path10 = __toESM(require("path"));
129934
- import_atomix_core7 = __toESM(require_dist4());
130467
+ import_atomix_core8 = __toESM(require_dist4());
129935
130468
  }
129936
130469
  });
129937
130470
 
@@ -130107,6 +130640,15 @@ async function askPositiveInt(ask, label, def) {
130107
130640
  console.log(red(" \u8BF7\u8F93\u5165\u6B63\u6574\u6570\uFF0C\u6216\u56DE\u8F66\u7528\u9ED8\u8BA4"));
130108
130641
  }
130109
130642
  }
130643
+ async function askOptionalTemperature(ask, defHint) {
130644
+ for (; ; ) {
130645
+ const raw = (await ask(` temperature [${gray("0\u20132,\u56DE\u8F66\u7528" + defHint)}${gray("]")}: `)).trim();
130646
+ if (!raw) return void 0;
130647
+ const n = Number(raw);
130648
+ if ((0, import_atomix_core9.isValidTemperature)(n)) return n;
130649
+ console.log(red(" \u8BF7\u8F93\u5165 0\u20132 \u7684\u6570\u5B57\uFF0C\u6216\u56DE\u8F66\u7528\u9ED8\u8BA4"));
130650
+ }
130651
+ }
130110
130652
  async function askSelect(ask, label, items, defaultIdx = 0) {
130111
130653
  items.forEach((it, i) => console.log(` ${cyan(String(i + 1))}. ${it}`));
130112
130654
  for (; ; ) {
@@ -130195,9 +130737,16 @@ async function runAddWizard(core, ask) {
130195
130737
  if (limits) console.log(gray(` \u5DF2\u6309\u6A21\u578B\u81EA\u52A8\u8BC6\u522B\u9650\u989D\uFF1AmaxTokens=${defMax} contextLength=${defCtx}`));
130196
130738
  const maxTokens = await askPositiveInt(ask, "maxTokens", defMax);
130197
130739
  const contextLength = await askPositiveInt(ask, "contextLength", defCtx);
130740
+ let temperature;
130741
+ if ((0, import_atomix_core9.modelForcesTemperatureOne)(modelName)) console.log(gray(" \u8BE5\u6A21\u578B\u53EA\u63A5\u53D7\u9ED8\u8BA4\u6E29\u5EA6 1\uFF0C\u8DF3\u8FC7 temperature"));
130742
+ else if ((0, import_atomix_core9.modelRejectsTemperature)(modelName)) console.log(gray(" \u8BE5\u6A21\u578B\u4E0D\u652F\u6301 temperature \u53C2\u6570\uFF0C\u8DF3\u8FC7"));
130743
+ else {
130744
+ if ((0, import_atomix_core9.modelTemperatureGatedByThinking)(modelName)) console.log(gray(" \u8BE5\u6A21\u578B\u4EC5 thinking \u5173\u95ED\u65F6\u4F7F\u7528 temperature\uFF0C\u5F00\u542F\u65F6\u4E0D\u53D1\u9001"));
130745
+ temperature = await askOptionalTemperature(ask, adapt === "anthropic" ? `\u9ED8\u8BA4 ${import_atomix_core9.DEFAULT_ANTHROPIC_TEMPERATURE}` : "\u670D\u52A1\u7AEF\u9ED8\u8BA4");
130746
+ }
130198
130747
  console.log(gray(" \u9A8C\u8BC1\u8FDE\u901A\u6027\u5E76\u4FDD\u5B58\u2026"));
130199
130748
  try {
130200
- await core.addModel({ provider, modelName, baseURL, apiKey, maxTokens, contextLength, adapt });
130749
+ await core.addModel({ provider, modelName, baseURL, apiKey, maxTokens, contextLength, adapt, ...temperature !== void 0 ? { temperature } : {} });
130201
130750
  } catch (e) {
130202
130751
  console.log(red(` \u6DFB\u52A0\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`));
130203
130752
  return false;
@@ -130224,13 +130773,33 @@ async function printModelList(core) {
130224
130773
  console.log(gray(" \uFF08\u65E0\u5DF2\u914D\u7F6E\u6A21\u578B\uFF0C`/model add` \u6DFB\u52A0\uFF09"));
130225
130774
  return;
130226
130775
  }
130776
+ const eff = effectiveModels(core);
130777
+ const profiles = new Map(core.getModelProfiles().map((p) => [p.name, p]));
130778
+ const tempOf = (name) => {
130779
+ const p = profiles.get(name);
130780
+ if (!p) return "";
130781
+ if ((0, import_atomix_core9.modelForcesTemperatureOne)(p.modelName)) return "temp=\u56FA\u5B9A1";
130782
+ if ((0, import_atomix_core9.modelRejectsTemperature)(p.modelName)) return "temp=\u4E0D\u652F\u6301";
130783
+ return p.temperature !== void 0 ? `temp=${p.temperature}` : "temp=\u9ED8\u8BA4";
130784
+ };
130227
130785
  for (const name of data.modelList) {
130228
- const marks = [
130229
- name === data.taskConfig?.main ? green("main") : "",
130230
- name === data.taskConfig?.quick ? cyan("quick") : ""
130231
- ].filter(Boolean).join(" ");
130232
- console.log(` ${marks ? "\u25CF " : " "}${name}${marks ? gray(" \u2190 ") + marks : ""}`);
130786
+ const marks = [];
130787
+ if (name === eff.main) marks.push(green(eff.mainFrom === "harness" ? "main(harness)" : "main"));
130788
+ else if (name === data.taskConfig?.main && eff.mainFrom === "harness") marks.push(gray("main(base)"));
130789
+ if (name === eff.quick) marks.push(cyan(eff.quickFrom === "harness" ? "quick(harness)" : "quick"));
130790
+ else if (name === data.taskConfig?.quick && eff.quickFrom === "harness") marks.push(gray("quick(base)"));
130791
+ const m = marks.join(" ");
130792
+ console.log(` ${m ? "\u25CF " : " "}${name}${gray(" " + tempOf(name))}${m ? gray(" \u2190 ") + m : ""}`);
130233
130793
  }
130794
+ console.log(gray(` temperature: ${temperatureStatusLine(core)}`));
130795
+ if (eff.fallback) {
130796
+ for (const slot of ["main", "quick"]) {
130797
+ if (eff.fallback[slot]) console.log(yellow(` \u26A0 harness \u58F0\u660E ${slot}=${eff.fallback[slot]} \u4E0D\u5B58\u5728,${slot} \u5DF2\u56DE\u843D base \u7684 ${eff[slot] || "-"}`));
130798
+ }
130799
+ }
130800
+ }
130801
+ function inHarness(core) {
130802
+ return isHarnessActive(core);
130234
130803
  }
130235
130804
  async function modelCommand(core, args, ask) {
130236
130805
  const [sub, ...rest2] = args;
@@ -130240,44 +130809,97 @@ async function modelCommand(core, args, ask) {
130240
130809
  case void 0:
130241
130810
  case "list":
130242
130811
  await printModelList(core);
130243
- if (!sub) console.log(gray(" \u7528\u6CD5\uFF1A/model list | add | use <\u540D\u79F0> | quick <\u540D\u79F0> | del <\u540D\u79F0>"));
130812
+ if (!sub) console.log(gray(" \u7528\u6CD5\uFF1A/model list | add | use <\u540D\u79F0> | quick <\u540D\u79F0> | temp [<\u540D\u79F0>] <\u503C|default> | del <\u540D\u79F0>"));
130244
130813
  break;
130245
130814
  case "add":
130246
130815
  await addModelWizard(core, ask);
130247
130816
  break;
130248
130817
  case "use": {
130249
130818
  if (!name) return console.log(red(" \u7528\u6CD5\uFF1A/model use <\u540D\u79F0>"));
130819
+ if (inHarness(core)) {
130820
+ console.log(green(` \u2713 ${setActiveHarnessModel(core, "main", name)}`));
130821
+ break;
130822
+ }
130250
130823
  const r = await core.switchModel(name);
130251
130824
  console.log(green(` \u2713 \u4E3B\u6A21\u578B \u2192 ${r.taskConfig.main}`));
130252
130825
  break;
130253
130826
  }
130254
130827
  case "quick": {
130255
130828
  if (!name) return console.log(red(" \u7528\u6CD5\uFF1A/model quick <\u540D\u79F0>"));
130829
+ if (inHarness(core)) {
130830
+ console.log(green(` \u2713 ${setActiveHarnessModel(core, "quick", name)}`));
130831
+ break;
130832
+ }
130256
130833
  const cur = await core.getModelData();
130257
130834
  const r = await core.applyTaskModel({ main: cur.taskConfig.main, quick: name });
130258
130835
  console.log(green(` \u2713 \u5FEB\u901F\u6A21\u578B \u2192 ${r.taskConfig.quick}`));
130259
130836
  break;
130260
130837
  }
130838
+ case "temp": {
130839
+ if (!rest2.length) {
130840
+ console.log(gray(` temperature: ${temperatureStatusLine(core)}`));
130841
+ console.log(gray(" \u7528\u6CD5\uFF1A/model temp <\u503C|default> | temp <\u6A21\u578B\u540D> <\u503C|default>"));
130842
+ break;
130843
+ }
130844
+ const parseVal = (s) => {
130845
+ if (s === "default") return null;
130846
+ const n = Number(s);
130847
+ if (!s || !(0, import_atomix_core9.isValidTemperature)(n)) throw new Error(`temperature \u987B\u4E3A 0\u20132 \u7684\u6570\u5B57\u6216 default\uFF0C\u6536\u5230 ${JSON.stringify(s)}`);
130848
+ return n;
130849
+ };
130850
+ const fmt = (v2) => v2 === null ? "\u9ED8\u8BA4" : String(v2);
130851
+ if (rest2.length >= 2) {
130852
+ const target = rest2.slice(0, -1).join(" ");
130853
+ const v2 = parseVal(rest2[rest2.length - 1]);
130854
+ await core.updateModel(target, { temperature: v2 ?? void 0 });
130855
+ console.log(green(` \u2713 ${target} \u7684 temperature \u2192 ${fmt(v2)}\uFF08model.conf\uFF09`));
130856
+ const eff = effectiveModels(core);
130857
+ const over2 = harnessTemperatureOverride(core);
130858
+ for (const slot of ["main", "quick"]) {
130859
+ if (eff[slot] === target && over2?.[slot] !== void 0) console.log(yellow(` \u26A0 \u5F53\u524D harness ${getActiveHarnessDir(core)} \u5BF9 ${slot} \u58F0\u660E\u4E86 temperature=${over2[slot]}\uFF0C\u4F18\u5148\u4E8E profile\uFF1B\u6539 harness \u7528 /model temp <\u503C>`));
130860
+ }
130861
+ break;
130862
+ }
130863
+ const v = parseVal(rest2[0]);
130864
+ if (inHarness(core)) {
130865
+ console.log(green(` \u2713 ${setActiveHarnessTemperature(core, "main", v)}`));
130866
+ break;
130867
+ }
130868
+ const main = effectiveModels(core).main;
130869
+ if (!main) return console.log(red(" \u5C1A\u672A\u914D\u7F6E\u4E3B\u6A21\u578B\uFF08/model add\uFF09"));
130870
+ await core.updateModel(main, { temperature: v ?? void 0 });
130871
+ console.log(green(` \u2713 ${main} \u7684 temperature \u2192 ${fmt(v)}\uFF08model.conf\uFF09`));
130872
+ break;
130873
+ }
130261
130874
  case "del": {
130262
130875
  if (!name) return console.log(red(" \u7528\u6CD5\uFF1A/model del <\u540D\u79F0>"));
130876
+ const decl = harnessModelDeclared(core);
130877
+ if (decl && (decl.main === name || decl.quick === name)) {
130878
+ return console.log(red(` \u6A21\u578B\u6B63\u5728\u88AB\u5F53\u524D harness ${getActiveHarnessDir(core)} \u58F0\u660E\u4F7F\u7528,\u65E0\u6CD5\u5220\u9664(\u5148\u6539\u5176 harness.yaml \u7684 model \u5B57\u6BB5)`));
130879
+ }
130263
130880
  await core.delModel(name);
130264
130881
  console.log(green(` \u2713 \u5DF2\u5220\u9664\uFF1A${name}`));
130882
+ const refs = harnessesReferencingModel(name);
130883
+ if (refs.length) console.log(yellow(` \u26A0 \u4EE5\u4E0B harness \u4ECD\u58F0\u660E\u8BE5\u6A21\u578B,\u4E0B\u6B21\u52A0\u8F7D\u4F1A\u56DE\u843D base:${refs.join(" / ")}(\u8BF7\u6539\u5176 harness.yaml \u7684 model \u5B57\u6BB5)`));
130265
130884
  break;
130266
130885
  }
130267
130886
  default:
130268
130887
  console.log(bold(` \u672A\u77E5\u5B50\u547D\u4EE4\uFF1A${sub}`));
130269
- console.log(gray(" \u7528\u6CD5\uFF1A/model list | add | use <\u540D\u79F0> | quick <\u540D\u79F0> | del <\u540D\u79F0>"));
130888
+ console.log(gray(" \u7528\u6CD5\uFF1A/model list | add | use <\u540D\u79F0> | quick <\u540D\u79F0> | temp [<\u540D\u79F0>] <\u503C|default> | del <\u540D\u79F0>"));
130270
130889
  }
130271
130890
  } catch (e) {
130272
130891
  console.log(red(` \u6A21\u578B\u64CD\u4F5C\u5931\u8D25\uFF1A${e instanceof Error ? e.message : String(e)}`));
130273
130892
  }
130274
130893
  }
130894
+ var import_atomix_core9;
130275
130895
  var init_modelWizard = __esm({
130276
130896
  "src/modelWizard.ts"() {
130277
130897
  "use strict";
130898
+ import_atomix_core9 = __toESM(require_dist4());
130278
130899
  init_ui();
130279
130900
  init_providers();
130280
130901
  init_cancellableAsk();
130902
+ init_harness();
130281
130903
  }
130282
130904
  });
130283
130905
 
@@ -131031,9 +131653,11 @@ ${cyan("atomix")}${usage2 ? " " + usage2 : ""} ${gray("\u276F")} `;
131031
131653
  case "/agents":
131032
131654
  console.log(gray(" " + await agentsCommand(core, rest2)));
131033
131655
  return void promptLoop();
131034
- case "/harness":
131035
- console.log(gray(" " + await harnessCommand(core, rest2)));
131656
+ case "/harness": {
131657
+ console.log(paintLines(" " + await harnessCommand(core, rest2)));
131658
+ if (rest2[0] === "use" || rest2[0] === "reset") thinkingEnabled = appliedThinking(core) ?? thinkingEnabled;
131036
131659
  return void promptLoop();
131660
+ }
131037
131661
  case "/memory":
131038
131662
  console.log(gray(" " + await memoryCommand(cwd, appConfig, rest2, { harnessMemory: harnessMemoryOverride(core), harnessPersona: harnessPersonaOverride(core), personaPath: getActivePersonaFile(core) })));
131039
131663
  return void promptLoop();
@@ -131050,9 +131674,11 @@ ${cyan("atomix")}${usage2 ? " " + usage2 : ""} ${gray("\u276F")} `;
131050
131674
  console.log(gray(` cwd ${cwd}`));
131051
131675
  console.log(gray(` harness ${getActiveHarnessName(core)}${isHarnessOverridden(core) ? "\uFF08\u4F1A\u8BDD\u7EA7\u6307\u5B9A\uFF09" : ""}`));
131052
131676
  console.log(gray(` memory ${memoryStatusLine(appConfig, { harnessMemory: harnessMemoryOverride(core), harnessPersona: harnessPersonaOverride(core) })}`));
131053
- console.log(gray(` model main=${md2?.taskConfig.main ?? "-"} quick=${md2?.taskConfig.quick ?? "-"}`));
131677
+ const modelLine = modelStatusLine(core);
131678
+ console.log((modelLine.startsWith("\u26A0") ? yellow : gray)(` model ${modelLine}`));
131679
+ console.log(gray(` temp ${temperatureStatusLine(core, thinkingEnabled)}`));
131054
131680
  console.log(gray(` context ${lastUsage ? `${lastUsage.useTokens} / ${lastUsage.maxTokens} tokens` : "-"}`));
131055
- console.log(gray(` thinking ${thinkingEnabled ? "on" : "off"}`));
131681
+ console.log(gray(` thinking ${thinkingStatusLine(core, thinkingEnabled)}`));
131056
131682
  console.log(gray(` perms ${permissionModeMeta(permissionMode).label}\uFF08${permissionMode}\uFF0CShift+Tab \u5207\u6362\uFF09`));
131057
131683
  return void promptLoop();
131058
131684
  }
@@ -131116,10 +131742,11 @@ ${cyan("atomix")}${usage2 ? " " + usage2 : ""} ${gray("\u276F")} `;
131116
131742
  });
131117
131743
  sessionId = session.ready.sessionId;
131118
131744
  lastUsage = session.ready.usage;
131745
+ thinkingEnabled = appliedThinking(core) ?? false;
131119
131746
  if (session.ready.projectInputHistory?.length) {
131120
131747
  rl.history = [...session.ready.projectInputHistory];
131121
131748
  }
131122
- for (const n of session.notes) console.log(n.startsWith("harness") ? yellow(` ${n}`) : gray(` ${n}`));
131749
+ for (const n of session.notes) console.log(n.startsWith("harness") ? yellow(` ${n}`) : paintLines(` ${n}`));
131123
131750
  if (resumeSessionId) {
131124
131751
  for (const item of loadReplay(cwd, resumeSessionId)) {
131125
131752
  if (item.role === "user") console.log("\n" + cyan("\u276F ") + gray(truncate2(item.text, 200)));
@@ -131424,7 +132051,7 @@ var init_serve = __esm({
131424
132051
  return this.entry(key);
131425
132052
  }
131426
132053
  info(key, e) {
131427
- return { sessionId: key, cwd: e.session.cwd, harness: e.session.harness, permissionMode: e.session.permissionMode, pending: e.inflight.size };
132054
+ return { sessionId: key, cwd: e.session.cwd, harness: e.session.harness, permissionMode: e.session.permissionMode, model: e.session.model, pending: e.inflight.size };
131428
132055
  }
131429
132056
  async open(p) {
131430
132057
  const cwd = this.resolveCwd(p.cwd, "cwd");
@@ -131811,10 +132438,10 @@ program2.command("marketplace").description("\u63D2\u4EF6\u5E02\u573A\uFF1Alist
131811
132438
  process.exit(0);
131812
132439
  });
131813
132440
  program2.command("model").description("\u6A21\u578B\u914D\u7F6E\u7BA1\u7406\uFF1Alist | add | use <\u540D\u79F0> | quick <\u540D\u79F0> | del <\u540D\u79F0>").argument("[args...]").action(async (args) => {
131814
- const { AtomixCore: AtomixCore2 } = await Promise.resolve().then(() => __toESM(require_dist4()));
132441
+ const { AtomixCore: AtomixCore3 } = await Promise.resolve().then(() => __toESM(require_dist4()));
131815
132442
  const { modelCommand: modelCommand2 } = await Promise.resolve().then(() => (init_modelWizard(), modelWizard_exports));
131816
132443
  const { makeCancellableAsk: makeCancellableAsk2 } = await Promise.resolve().then(() => (init_cancellableAsk(), cancellableAsk_exports));
131817
- const core = new AtomixCore2({ workingDir: process.cwd(), logLevel: atomixLogLevel(), skipMCPInit: true });
132444
+ const core = new AtomixCore3({ workingDir: process.cwd(), logLevel: atomixLogLevel(), skipMCPInit: true });
131818
132445
  const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
131819
132446
  const { ask, dispose } = makeCancellableAsk2(rl);
131820
132447
  try {