@yeaft/webchat-agent 0.1.1000 → 0.1.1002

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.1000",
3
+ "version": "0.1.1002",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/yeaft/effort.js CHANGED
@@ -61,7 +61,7 @@ export const SCENARIO_EFFORT = Object.freeze({
61
61
  * Pick the effort level for a given query context.
62
62
  *
63
63
  * Decision order:
64
- * 1. If userEffort is a valid Effort ('low'|'medium'|'high'|'max'),
64
+ * 1. If userEffort is a valid Effort ('minimal'|'low'|'medium'|'high'|'max'),
65
65
  * return it unchanged. This is the explicit override path —
66
66
  * `/max` prefix, Settings slider, or API caller.
67
67
  * 2. If toolLoopTurns >= LONG_LOOP_TURN_THRESHOLD, upgrade the
@@ -74,7 +74,7 @@ export const SCENARIO_EFFORT = Object.freeze({
74
74
  * already consumed in the current `query()` call.
75
75
  * @param {unknown} [ctx.userEffort=null] — User-supplied override.
76
76
  * Invalid values are ignored (fall through to scenario path).
77
- * @returns {'low'|'medium'|'high'|'max'} Resolved effort. Never null —
77
+ * @returns {'minimal'|'low'|'medium'|'high'|'max'} Resolved effort. Never null —
78
78
  * the adapter/router is responsible for dropping it when the
79
79
  * feature flag is off or the model doesn't support thinking.
80
80
  */
@@ -3,6 +3,7 @@ export const GITHUB_COPILOT_BASE_URL = 'https://api.githubcopilot.com';
3
3
  export const GITHUB_COPILOT_CREDENTIAL_PROVIDER = 'github-copilot';
4
4
 
5
5
  export const FALLBACK_GITHUB_COPILOT_MODELS = [
6
+ 'gpt-5.5',
6
7
  'gpt-5.4',
7
8
  'gpt-5.4-mini',
8
9
  'gpt-5-mini',
@@ -52,9 +52,9 @@ function thinkingV1Enabled() {
52
52
  }
53
53
 
54
54
  /**
55
- * Translate a normalised effort ('low'|'medium'|'high'|'max') into the value
55
+ * Translate a normalised effort ('minimal'|'low'|'medium'|'high'|'max') into the value
56
56
  * accepted by the OpenAI Responses `reasoning.effort` field. Responses today
57
- * accepts 'low'|'medium'|'high' — 'max' degrades to 'high' to match the
57
+ * accepts 'minimal'|'low'|'medium'|'high' — 'max' degrades to 'high' to match the
58
58
  * registry's normaliseEffort downgrade rule.
59
59
  */
60
60
  function effortForResponses(effort) {
@@ -22,7 +22,7 @@
22
22
  */
23
23
 
24
24
  import { LLMAdapter } from './adapter.js';
25
- import { getThinkingCapability, normalizeEffort, parseModelRef } from '../models.js';
25
+ import { getModelEffortOptions, getThinkingCapability, normalizeEffort, parseModelRef } from '../models.js';
26
26
  import { normalizeKnownProviderForRuntime } from './known-providers.js';
27
27
  import { pairSanitize } from '../pair-sanitize.js';
28
28
 
@@ -109,11 +109,16 @@ export function filterEffortForModel(params) {
109
109
  const { effort: _drop, effortSource: _source, ...rest } = params;
110
110
  return rest;
111
111
  }
112
- const cap = getThinkingCapability(parseModelRef(params.model).modelId);
112
+ const modelId = parseModelRef(params.model).modelId;
113
+ const cap = getThinkingCapability(modelId);
113
114
  if (!cap.supportsThinking || cap.thinkingProtocol === 'none') {
114
115
  const { effort: _drop, effortSource: _source, ...rest } = params;
115
116
  return rest;
116
117
  }
118
+ if (norm === 'minimal' && !getModelEffortOptions(modelId).includes('minimal')) {
119
+ const { effort: _drop, effortSource: _source, ...rest } = params;
120
+ return rest;
121
+ }
117
122
  return { ...params, effort: norm, effortSource: params.effortSource };
118
123
  }
119
124
 
package/yeaft/models.js CHANGED
@@ -131,6 +131,18 @@ export const MODEL_REGISTRY = new Map([
131
131
  adapter: 'openai-responses',
132
132
  baseUrl: 'https://api.openai.com/v1',
133
133
  displayName: 'GPT-5.4',
134
+ supportsThinking: true,
135
+ thinkingProtocol: 'openai-reasoning',
136
+ defaultEffort: null,
137
+ }],
138
+ ['gpt-5.5', {
139
+ provider: 'openai',
140
+ adapter: 'openai-responses',
141
+ baseUrl: 'https://api.openai.com/v1',
142
+ displayName: 'GPT-5.5',
143
+ supportsThinking: true,
144
+ thinkingProtocol: 'openai-reasoning',
145
+ defaultEffort: null,
134
146
  }],
135
147
  ['gpt-4.1', {
136
148
  provider: 'openai',
@@ -371,7 +383,7 @@ export function parseModelRef(ref) {
371
383
 
372
384
  /**
373
385
  * Valid effort levels accepted by Yeaft adapters.
374
- * @typedef {'low' | 'medium' | 'high' | 'max'} Effort
386
+ * @typedef {'minimal' | 'low' | 'medium' | 'high' | 'max'} Effort
375
387
  */
376
388
 
377
389
  /**
@@ -396,11 +408,12 @@ export const ANTHROPIC_THINKING_BUDGETS = {
396
408
  * but the adapter MUST NOT error.
397
409
  *
398
410
  * @param {Effort} effort
399
- * @returns {'low' | 'medium' | 'high' | null}
411
+ * @returns {'minimal' | 'low' | 'medium' | 'high' | null}
400
412
  */
401
413
  export function mapEffortToOpenAIReasoning(effort) {
402
414
  if (!effort) return null;
403
415
  switch (effort) {
416
+ case 'minimal': return 'minimal';
404
417
  case 'low': return 'low';
405
418
  case 'medium': return 'medium';
406
419
  case 'high': return 'high';
@@ -411,7 +424,8 @@ export function mapEffortToOpenAIReasoning(effort) {
411
424
  }
412
425
  }
413
426
 
414
- export const MODEL_EFFORT_OPTIONS = ['low', 'medium', 'high'];
427
+ export const OPENAI_REASONING_EFFORT_OPTIONS = ['minimal', 'low', 'medium', 'high'];
428
+ export const ANTHROPIC_EFFORT_OPTIONS = ['low', 'medium', 'high'];
415
429
 
416
430
  function inferThinkingCapability(model) {
417
431
  const id = parseModelRef(model).modelId.toLowerCase();
@@ -485,7 +499,9 @@ export function getThinkingCapability(model) {
485
499
  export function getModelEffortOptions(model) {
486
500
  const cap = getThinkingCapability(model);
487
501
  if (!cap.supportsThinking || cap.thinkingProtocol === 'none') return [];
488
- return MODEL_EFFORT_OPTIONS.slice();
502
+ if (cap.thinkingProtocol === 'openai-reasoning') return OPENAI_REASONING_EFFORT_OPTIONS.slice();
503
+ if (cap.thinkingProtocol === 'anthropic') return ANTHROPIC_EFFORT_OPTIONS.slice();
504
+ return [];
489
505
  }
490
506
 
491
507
  export function modelSupportsEffort(model) {
@@ -499,7 +515,7 @@ export function modelSupportsEffort(model) {
499
515
  * @returns {Effort | null}
500
516
  */
501
517
  export function normalizeEffort(effort) {
502
- if (effort === 'low' || effort === 'medium' || effort === 'high' || effort === 'max') {
518
+ if (effort === 'minimal' || effort === 'low' || effort === 'medium' || effort === 'high' || effort === 'max') {
503
519
  return effort;
504
520
  }
505
521
  return null;
@@ -28,7 +28,7 @@ const CONFIG_FILE = 'config.json';
28
28
 
29
29
  /** Whitelist of persisted session model-override fields. Reject everything else. */
30
30
  const ALLOWED_KEYS = new Set(['model', 'modelEffort']);
31
- const ALLOWED_EFFORTS = new Set(['low', 'medium', 'high']);
31
+ const ALLOWED_EFFORTS = new Set(['minimal', 'low', 'medium', 'high']);
32
32
 
33
33
  export class SessionConfigError extends Error {
34
34
  constructor(code, message) {
@@ -101,7 +101,7 @@ export function validateSessionConfig(cfg) {
101
101
  }
102
102
  if ('modelEffort' in cfg && cfg.modelEffort !== null && cfg.modelEffort !== undefined && cfg.modelEffort !== '') {
103
103
  if (typeof cfg.modelEffort !== 'string' || !ALLOWED_EFFORTS.has(cfg.modelEffort.trim())) {
104
- throw new SessionConfigError('invalid_model_effort', 'modelEffort must be low, medium, or high');
104
+ throw new SessionConfigError('invalid_model_effort', 'modelEffort must be minimal, low, medium, or high');
105
105
  }
106
106
  }
107
107
  }
@@ -3983,6 +3983,11 @@ export function handleYeaftModelSwitch(msg) {
3983
3983
  session.config.model = msg.model;
3984
3984
  session.config.primaryModel = msg.model;
3985
3985
  session.config.modelEffort = msg.modelEffort || null;
3986
+ // Legacy non-session model switches mutate the shared root config instead
3987
+ // of going through handleYeaftUpdateSessionConfig(), so cached per-VP
3988
+ // Engines would otherwise keep the old effective config and drop newly
3989
+ // selected effort values until process restart.
3990
+ vpEngines.clear();
3986
3991
 
3987
3992
  sendSessionEvent({
3988
3993
  type: 'model_switched',