@yeaft/webchat-agent 0.1.490 → 0.1.491

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/crew/routing.js +33 -9
  2. package/package.json +1 -1
package/crew/routing.js CHANGED
@@ -43,10 +43,13 @@ export function parseRoutes(text) {
43
43
  // Replaces ```...``` content with whitespace of same length to preserve positions
44
44
  text = text.replace(/```[\s\S]*?```/g, m => ' '.repeat(m.length));
45
45
 
46
- // ─── Phase 1: Standard ROUTE blocks (with END_ROUTE) ──────────
47
- // ★ Tolerate both underscore and space variants: ---END_ROUTE--- or ---END ROUTE---
48
- // ★ Use negative lookahead to not cross another ---ROUTE--- boundary
49
- const regex = /---ROUTE---\s*\n((?:(?!---ROUTE---)[\s\S])*?)---END[_ ]ROUTE---/g;
46
+ // ─── Phase 1: Standard ROUTE blocks (with closing marker) ─────
47
+ // ★ Tolerate closer variants:
48
+ // ---END_ROUTE--- (underscore)
49
+ // ---END ROUTE--- (space)
50
+ // ---END--- (bare — users / PM often write this)
51
+ // ★ Use negative lookahead to not cross another ---ROUTE--- boundary.
52
+ const regex = /---ROUTE---\s*\n((?:(?!---ROUTE---)[\s\S])*?)---END(?:[_ ]ROUTE)?---/g;
50
53
  let match;
51
54
  const matchedRanges = []; // track matched ranges to avoid double-parsing
52
55
 
@@ -56,9 +59,12 @@ export function parseRoutes(text) {
56
59
  if (parsed) routes.push(parsed);
57
60
  }
58
61
 
59
- // ─── Phase 2: Fallback — ROUTE block missing END_ROUTE ────────
60
- // Match ---ROUTE--- without a closing ---END_ROUTE---
61
- // Take content until next ---ROUTE--- or EOF
62
+ // ─── Phase 2: Fallback — ROUTE block missing any closing marker ──
63
+ // Take content until (a) next ---ROUTE--- boundary, (b) first blank
64
+ // line (summary is almost always a single paragraph — anything after
65
+ // a blank line is kanban/recent-routes/task-context noise injected
66
+ // by the crew runtime), or (c) EOF. The blank-line cutoff prevents
67
+ // the whole back-injected blob from being swallowed as the summary.
62
68
  const openRegex = /---ROUTE---\s*\n/g;
63
69
  while ((match = openRegex.exec(text)) !== null) {
64
70
  // Skip if this range was already captured by Phase 1
@@ -68,7 +74,10 @@ export function parseRoutes(text) {
68
74
  const blockStart = pos + match[0].length;
69
75
  // End at next ---ROUTE--- or EOF
70
76
  const nextRoute = text.indexOf('---ROUTE---', blockStart);
71
- const blockEnd = nextRoute !== -1 ? nextRoute : text.length;
77
+ const hardEnd = nextRoute !== -1 ? nextRoute : text.length;
78
+ // Soft end: first blank line (two or more newlines with only whitespace in between).
79
+ const blank = text.slice(blockStart, hardEnd).search(/\n[ \t]*\n/);
80
+ const blockEnd = blank !== -1 ? blockStart + blank : hardEnd;
72
81
  const block = text.slice(blockStart, blockEnd);
73
82
 
74
83
  const parsed = _parseRouteBlock(block);
@@ -88,7 +97,8 @@ export function parseRoutes(text) {
88
97
  const lastRouteOpen = precedingText.lastIndexOf('---ROUTE---');
89
98
  const lastRouteClose = Math.max(
90
99
  precedingText.lastIndexOf('---END_ROUTE---'),
91
- precedingText.lastIndexOf('---END ROUTE---')
100
+ precedingText.lastIndexOf('---END ROUTE---'),
101
+ precedingText.lastIndexOf('---END---')
92
102
  );
93
103
  if (lastRouteOpen > lastRouteClose) continue; // inside an open block
94
104
 
@@ -122,6 +132,20 @@ function _parseRouteBlock(block) {
122
132
  const taskTitleMatch = block.match(/^taskTitle:\s*(.+)/im);
123
133
 
124
134
  let summary = summaryMatch ? summaryMatch[1].trim() : '';
135
+
136
+ // ★ Bare-body fallback — PM / humans often omit the `summary:` label and
137
+ // just write the message as free text AFTER the known fields. Collect
138
+ // everything that is NOT a recognised field line as the body.
139
+ if (!summary) {
140
+ const KNOWN_FIELD = /^\s*(?:to|task|taskTitle|summary)\s*:/i;
141
+ const bare = block
142
+ .split(/\r?\n/)
143
+ .filter(line => !KNOWN_FIELD.test(line))
144
+ .join('\n')
145
+ .trim();
146
+ if (bare) summary = bare;
147
+ }
148
+
125
149
  if (!summary) {
126
150
  summary = '[该角色未提供消息摘要]';
127
151
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.490",
3
+ "version": "0.1.491",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",