@yeaft/webchat-agent 0.1.489 → 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.
- package/crew/routing.js +33 -9
- package/package.json +1 -1
- package/unify/eval/cases/e2e.js +0 -2
- package/unify/eval/cases/tool-use.js +0 -5
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
|
|
47
|
-
// ★ Tolerate
|
|
48
|
-
//
|
|
49
|
-
|
|
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
|
|
60
|
-
//
|
|
61
|
-
//
|
|
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
|
|
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
package/unify/eval/cases/e2e.js
CHANGED
|
@@ -23,7 +23,6 @@ const listProjectsTool = defineTool({
|
|
|
23
23
|
name: 'list_projects',
|
|
24
24
|
description: 'List all projects in the workspace.',
|
|
25
25
|
parameters: { type: 'object', properties: {} },
|
|
26
|
-
modes: ['chat', 'work'],
|
|
27
26
|
async execute() {
|
|
28
27
|
return JSON.stringify({
|
|
29
28
|
projects: ['my-app', 'shared-lib', 'docs-site'],
|
|
@@ -41,7 +40,6 @@ const getProjectInfoTool = defineTool({
|
|
|
41
40
|
},
|
|
42
41
|
required: ['name'],
|
|
43
42
|
},
|
|
44
|
-
modes: ['chat', 'work'],
|
|
45
43
|
async execute(input) {
|
|
46
44
|
const projects = {
|
|
47
45
|
'my-app': { name: 'my-app', language: 'TypeScript', framework: 'Express', tests: 142 },
|
|
@@ -33,7 +33,6 @@ const searchTool = defineTool({
|
|
|
33
33
|
},
|
|
34
34
|
required: ['query'],
|
|
35
35
|
},
|
|
36
|
-
modes: ['chat', 'work'],
|
|
37
36
|
async execute(input) {
|
|
38
37
|
const q = (input.query || '').slice(0, 200);
|
|
39
38
|
return JSON.stringify({
|
|
@@ -54,7 +53,6 @@ const calculatorTool = defineTool({
|
|
|
54
53
|
},
|
|
55
54
|
required: ['expression'],
|
|
56
55
|
},
|
|
57
|
-
modes: ['chat', 'work'],
|
|
58
56
|
async execute(input) {
|
|
59
57
|
try {
|
|
60
58
|
// Safe eval for basic math
|
|
@@ -76,7 +74,6 @@ const readFileTool = defineTool({
|
|
|
76
74
|
},
|
|
77
75
|
required: ['path'],
|
|
78
76
|
},
|
|
79
|
-
modes: ['chat', 'work'],
|
|
80
77
|
async execute(input) {
|
|
81
78
|
// Mock file system
|
|
82
79
|
const files = {
|
|
@@ -99,7 +96,6 @@ const writeFileTool = defineTool({
|
|
|
99
96
|
},
|
|
100
97
|
required: ['path', 'content'],
|
|
101
98
|
},
|
|
102
|
-
modes: ['work'],
|
|
103
99
|
async execute(input) {
|
|
104
100
|
return `Successfully wrote ${input.content.length} bytes to ${input.path}`;
|
|
105
101
|
},
|
|
@@ -115,7 +111,6 @@ const bashTool = defineTool({
|
|
|
115
111
|
},
|
|
116
112
|
required: ['command'],
|
|
117
113
|
},
|
|
118
|
-
modes: ['work'],
|
|
119
114
|
async execute(input) {
|
|
120
115
|
// Mock bash responses
|
|
121
116
|
const responses = {
|