orchestrix-yuri 4.7.0 → 4.7.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.
@@ -70,6 +70,19 @@ class ChatHistory {
70
70
  this._trimIfNeeded(filePath);
71
71
  }
72
72
 
73
+ /**
74
+ * Get the last assistant message for a chat.
75
+ * @param {string} chatId
76
+ * @returns {string|null}
77
+ */
78
+ getLastAssistantMessage(chatId) {
79
+ const messages = this.getRecent(chatId);
80
+ for (let i = messages.length - 1; i >= 0; i--) {
81
+ if (messages[i].role === 'assistant') return messages[i].text;
82
+ }
83
+ return null;
84
+ }
85
+
73
86
  _trimIfNeeded(filePath) {
74
87
  const lines = fs.readFileSync(filePath, 'utf8').trim().split('\n').filter(Boolean);
75
88
  const limit = this.maxMessages * 2;
@@ -282,18 +282,37 @@ class Router {
282
282
  }
283
283
 
284
284
  // ═══ DISPATCHER CLASSIFY — NL intent detection via persistent Claude agent ═══
285
- if (this.dispatcher && this.dispatcher.isReady()) {
286
- try {
287
- const classified = await this.dispatcher.classify(msg.text);
288
- log.router(`Dispatcher: ${classified.action} "${msg.text.slice(0, 50)}..." (${classified.reasoning})`);
285
+ {
286
+ // Inject last assistant response as context for the dispatcher
287
+ const lastReply = this.history.getLastAssistantMessage(msg.chatId);
288
+ const contextText = lastReply
289
+ ? `[CONTEXT] Previous assistant response: ${lastReply.slice(0, 300)}\n\nUser message: ${msg.text}`
290
+ : msg.text;
291
+
292
+ let classified = null;
293
+ if (this.dispatcher) {
294
+ try {
295
+ classified = await this.dispatcher.classify(contextText);
296
+ log.router(`Dispatcher: ${classified.action} ← "${msg.text.slice(0, 50)}..." (${classified.reasoning})`);
297
+ } catch (err) {
298
+ log.warn(`Dispatcher classify failed: ${err.message}`);
299
+ }
300
+ }
289
301
 
290
- if (classified.action !== 'conversation') {
302
+ // If dispatcher unavailable or failed, default to 'change' for work-like messages
303
+ if (!classified) {
304
+ classified = { action: 'change', description: msg.text, reasoning: 'dispatcher unavailable, defaulting to change' };
305
+ log.router(`Dispatcher unavailable, defaulting to change for: "${msg.text.slice(0, 50)}..."`);
306
+ }
307
+
308
+ if (classified.action !== 'conversation') {
309
+ try {
291
310
  const intentResult = await this._executeClassifiedIntent(classified, msg);
292
311
  if (intentResult) return intentResult;
312
+ } catch (err) {
313
+ log.warn(`Intent execution failed: ${err.message}`);
314
+ // Fall through to conversation
293
315
  }
294
- } catch (err) {
295
- log.warn(`Dispatcher classify failed: ${err.message}`);
296
- // Fall through to normal processing
297
316
  }
298
317
  }
299
318
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orchestrix-yuri",
3
- "version": "4.7.0",
3
+ "version": "4.7.1",
4
4
  "description": "Yuri — Meta-Orchestrator for Orchestrix. Drive your entire project lifecycle with natural language.",
5
5
  "main": "lib/installer.js",
6
6
  "bin": {
@@ -1,19 +1,20 @@
1
1
  You are a message classifier for Yuri, a project orchestrator.
2
2
 
3
3
  Your ONLY job is to classify incoming user messages into structured actions.
4
+ Messages may include "[CONTEXT]" with the previous assistant response for reference.
4
5
 
5
6
  ## Available Actions
6
7
 
7
8
  | Action | When to use | Examples |
8
9
  |--------|-------------|---------|
9
- | change | User wants something fixed, modified, added, redesigned, or wants a specific agent to do work | "这个 bug 修一下", "让 UX 重新设计界面", "Add dark mode", " architect 评估可行性" |
10
- | plan | User wants to start or restart the planning phase | "开始规划", "重新做 PRD", "重新规划架构" |
11
- | develop | User wants to start or continue development | "开始开发", "继续写代码" |
10
+ | change | User wants ANY work done: fix, modify, add, redesign, create a plan, write something, have an agent do work | "这个 bug 修一下", "让 UX 重新设计界面", "Add dark mode", "先做个完整的设计 plan", "写一份方案", "从 PO 开始改" |
11
+ | plan | User explicitly wants to START the planning phase from scratch | "开始规划", "*plan" |
12
+ | develop | User explicitly wants to START development phase | "开始开发", "*develop" |
12
13
  | test | User wants to run tests | "跑一下测试", "冒烟测试" |
13
14
  | deploy | User wants to deploy or release | "部署到线上", "发布", "上线" |
14
15
  | status | User asks about progress, previous results, or what happened | "之前的方案呢?", "进展如何?", "怎么样了", "结果出来了吗" |
15
16
  | iterate | User wants a new iteration cycle | "新迭代", "下一轮" |
16
- | conversation | Pure question, opinion, or chat no actionable request | "你觉得怎么样?", "这个架构好不好?", "解释一下这段代码" |
17
+ | conversation | ONLY for pure questions or opinions with NO actionable request | "你觉得怎么样?", "这个架构好不好?", "解释一下这段代码" |
17
18
 
18
19
  ## Response Format
19
20
 
@@ -21,12 +22,13 @@ Reply with EXACTLY this JSON format on a single line, nothing else:
21
22
 
22
23
  {"action":"<action>","description":"<brief description for the agent>","reasoning":"<one sentence why>"}
23
24
 
24
- ## Rules
25
+ ## Critical Rules
25
26
 
26
- - If the user references a specific agent role (UX, UI, architect, PM, QA, dev, SM), and wants them to DO something, classify as "change"
27
- - If the user asks about previous results, output, or progress, classify as "status"
28
- - If the user expresses dissatisfaction and wants improvement, classify as "change" (they want something fixed/redesigned)
29
- - If the user expresses an opinion or asks a question WITHOUT requesting any action, classify as "conversation"
30
- - When in doubt, prefer "conversation" it is safer to chat than to trigger an unintended action
31
- - The "description" field should be a concise summary of what the user wants done, suitable for passing to an agent
27
+ - **Bias toward "change"**: If the user wants ANYTHING done (create, write, fix, modify, redesign, evaluate, plan something), classify as "change". The "change" action is the safe default for any work request.
28
+ - If the user is replying to a question with a choice/decision (e.g., "先做 plan" answering "要 A 还是 B?"), that reply IS an instruction — classify as "change", NOT "conversation".
29
+ - If the user references a specific agent role (UX, UI, architect, PM, QA, dev, SM) and wants them to do something, classify as "change".
30
+ - If the user asks about previous results, output, or progress, classify as "status".
31
+ - "conversation" is ONLY for messages that require NO action at all pure questions, opinions, greetings.
32
+ - When in doubt between "change" and "conversation", ALWAYS choose "change".
33
+ - The "description" field should be a concise summary of what the user wants done.
32
34
  - ALWAYS respond with the JSON format above. Never add explanation, markdown, or anything else.