openvisio-agent 0.6.0 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/watch.mjs +22 -15
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openvisio-agent",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "description": "Connect your coding agent (Claude Code) to an OpenVisio team — MCP tools + optional autonomy — in one command. No shell scripts.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/watch.mjs CHANGED
@@ -344,21 +344,24 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, mcpConfig, wor
344
344
  if (x === 'opus' || x === 'sonnet' || x === 'haiku') return x
345
345
  return /^claude-[a-z0-9.\-\[\]]+$/i.test(x) ? x : null
346
346
  }
347
+ // Optional target tier: "chat"/"lite" → chat cycles only, "code"/"full" → code
348
+ // cycles only, absent → both.
349
+ const parseTarget = (t) => t && /^(chat|lite)$/i.test(t) ? 'chat' : t && /^(code|full)$/i.test(t) ? 'code' : 'both'
347
350
  const parseModelCmd = (text) => {
348
- // Slash form is unambiguous: "/model" (report) or "/model <name>".
349
- const slash = /(?:^|\s)\/model\b(?:\s+(\S+))?/i.exec(text)
350
- if (slash) { const a = slash[1]; if (!a) return { report: true }; const n = normalizeModel(a); return n ? { set: n } : { invalid: a } }
351
+ // Slash form is unambiguous: "/model" (report), "/model <name>", "/model chat <name>".
352
+ const slash = /(?:^|\s)\/model\b(?:\s+(chat|lite|code|full))?(?:\s+(\S+))?/i.exec(text)
353
+ if (slash) { const name = slash[2]; if (!name) return { report: true }; const n = normalizeModel(name); return n ? { set: n, target: parseTarget(slash[1]) } : { invalid: name } }
351
354
  // Natural language: only when a VALID model name is explicitly given after the
352
355
  // word "model" — so "use the model file in the repo" does NOT switch anything.
353
- const nl = /\b(?:set|switch|change|use)\s+(?:the\s+|your\s+)?model\s+(?:to\s+)?(\S+)/i.exec(text)
354
- if (nl) { const n = normalizeModel(nl[1]); if (n) return { set: n } }
356
+ const nl = /\b(?:set|switch|change|use)\s+(?:the\s+|your\s+)?(chat|code)?\s*model\s+(?:to\s+)?(\S+)/i.exec(text)
357
+ if (nl) { const n = normalizeModel(nl[2]); if (n) return { set: n, target: parseTarget(nl[1]) } }
355
358
  if (/\b(?:which|what)\s+model\s+(?:are\s+you|do\s+you|you\b)/i.test(text)) return { report: true }
356
359
  return null
357
360
  }
358
- // Persist a model change so a restart / the background service keeps it.
359
- const persistModel = (mdl) => {
361
+ // Persist the current model tiers so a restart / the background service keeps them.
362
+ const persistModel = () => {
360
363
  if (!slug) return
361
- try { writeJson(configPath(slug), { ...(readConfig(slug) || {}), model: mdl, chatModel: mdl }, true) } catch { /* best-effort */ }
364
+ try { writeJson(configPath(slug), { ...(readConfig(slug) || {}), model: codeModel, chatModel: liteModel !== codeModel ? liteModel : '' }, true) } catch { /* best-effort */ }
362
365
  }
363
366
 
364
367
  function onEvent(k, d) {
@@ -403,16 +406,20 @@ function loopBackendWs({ wsUrl, apiKey, identifier, slug, claude, mcpConfig, wor
403
406
  if (mcmd) {
404
407
  const thread = threadRoot != null ? `, parent_id ${threadRoot}` : ''
405
408
  if (mcmd.report) {
406
- log('model query → ' + codeModel + (liteModel !== codeModel ? ' / chat ' + liteModel : ''))
407
- void drain('fast', `An engineer asked which model you're running. Reply once in channel ${cid}${thread} (with your agent creds): "I'm currently running on ${codeModel}${liteModel !== codeModel ? ` (chat replies on ${liteModel})` : ''}." One line. Then stop.`)
409
+ log('model query → code ' + codeModel + ' / chat ' + liteModel)
410
+ void drain('fast', `An engineer asked which model you're running. Reply once in channel ${cid}${thread} (with your agent creds): "I'm on ${codeModel} for code work${liteModel !== codeModel ? ` and ${liteModel} for chat replies` : ' (and chat)'}." One line. Then stop.`)
408
411
  } else if (mcmd.invalid) {
409
412
  void drain('fast', `An engineer tried to switch your model to "${mcmd.invalid}", which isn't one you recognize. Reply once in channel ${cid}${thread} (with your agent creds): say you support "opus", "sonnet", "haiku", or a full "claude-…" id, and ask which they meant. One line. Then stop.`)
410
413
  } else {
411
- const prev = codeModel
412
- codeModel = mcmd.set; liteModel = mcmd.set
413
- persistModel(mcmd.set)
414
- log('model switched ' + prev + '' + codeModel + (who ? ' (by ' + who + ')' : ''))
415
- void drain('fast', `An engineer switched your underlying model to "${codeModel}" it is now active for your next actions. Post ONE short confirmation in channel ${cid}${thread} (with your agent creds): e.g. "Switched to ${codeModel} — I'll run on it from here." Then stop.`)
414
+ const tgt = mcmd.target // 'chat' | 'code' | 'both'
415
+ const prev = `code ${codeModel}/chat ${liteModel}`
416
+ if (tgt === 'chat') liteModel = mcmd.set
417
+ else if (tgt === 'code') codeModel = mcmd.set
418
+ else { codeModel = mcmd.set; liteModel = mcmd.set }
419
+ persistModel()
420
+ const label = tgt === 'chat' ? 'chat model' : tgt === 'code' ? 'code model' : 'model'
421
+ log('model switched (' + tgt + ') ' + prev + ' → code ' + codeModel + '/chat ' + liteModel + (who ? ' (by ' + who + ')' : ''))
422
+ void drain('fast', `An engineer switched your ${label} to "${mcmd.set}" — active for your next ${tgt === 'chat' ? 'chat replies' : tgt === 'code' ? 'code cycles' : 'actions'}. Post ONE short confirmation in channel ${cid}${thread} (with your agent creds): e.g. "Switched my ${label} to ${mcmd.set} — I'll use it from here." Then stop.`)
416
423
  }
417
424
  return
418
425
  }