crewly 1.20.30 → 1.20.31

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.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Strip tool-call markup an LLM emitted as prose.
3
+ *
4
+ * Models occasionally write their function-call envelope into the *text*
5
+ * part of a turn instead of (or as well as) making a real tool call. For a
6
+ * PTY runtime nobody sees it, but the in-process Crewly Agent forwards its
7
+ * text straight to Slack and chat, so the user gets a wall of
8
+ * `<invoke name="Bash">…` instead of an answer (2026-09-19, #crewly-support).
9
+ *
10
+ * This removes those envelopes — `function_calls` wrappers, `invoke`
11
+ * blocks and stray `parameter` tags, with or without a namespace prefix —
12
+ * while leaving fenced code blocks untouched, so an agent that is
13
+ * deliberately *explaining* the syntax keeps its example.
14
+ *
15
+ * @module utils/tool-call-markup
16
+ */
17
+ /** Result of {@link stripToolCallMarkup}. */
18
+ export interface StrippedText {
19
+ /** The text with tool-call envelopes removed and whitespace tidied. */
20
+ text: string;
21
+ /** True when something was removed. */
22
+ stripped: boolean;
23
+ }
24
+ /**
25
+ * Whether a string contains something that looks like a tool-call envelope.
26
+ *
27
+ * @param raw - Candidate text
28
+ * @returns True when an `invoke` / `function_calls` tag is present
29
+ */
30
+ export declare function hasToolCallMarkup(raw: string): boolean;
31
+ /**
32
+ * Remove tool-call markup from an agent's text response.
33
+ *
34
+ * Fenced code blocks (``` … ```) are passed through untouched: markup
35
+ * inside them is an example the agent meant to show.
36
+ *
37
+ * @param raw - The agent's text
38
+ * @returns The cleaned text and whether anything was removed
39
+ *
40
+ * @example
41
+ * stripToolCallMarkup('Working on it.\n<invoke name="Bash">…</invoke>')
42
+ * // → { text: 'Working on it.', stripped: true }
43
+ */
44
+ export declare function stripToolCallMarkup(raw: string): StrippedText;
45
+ //# sourceMappingURL=tool-call-markup.utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call-markup.utils.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/tool-call-markup.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AA+BH,6CAA6C;AAC7C,MAAM,WAAW,YAAY;IAC3B,uEAAuE;IACvE,IAAI,EAAE,MAAM,CAAC;IACb,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAwB7D"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Strip tool-call markup an LLM emitted as prose.
3
+ *
4
+ * Models occasionally write their function-call envelope into the *text*
5
+ * part of a turn instead of (or as well as) making a real tool call. For a
6
+ * PTY runtime nobody sees it, but the in-process Crewly Agent forwards its
7
+ * text straight to Slack and chat, so the user gets a wall of
8
+ * `<invoke name="Bash">…` instead of an answer (2026-09-19, #crewly-support).
9
+ *
10
+ * This removes those envelopes — `function_calls` wrappers, `invoke`
11
+ * blocks and stray `parameter` tags, with or without a namespace prefix —
12
+ * while leaving fenced code blocks untouched, so an agent that is
13
+ * deliberately *explaining* the syntax keeps its example.
14
+ *
15
+ * @module utils/tool-call-markup
16
+ */
17
+ /** Tag names that only ever appear in a tool-call envelope. */
18
+ const ENVELOPE_TAGS = ['function_calls', 'invoke', 'parameter'];
19
+ /**
20
+ * A tag like `<invoke …>`, `</invoke>`, `<||antml||invoke>` —
21
+ * any junk/namespace before the name, anything but `<`/`>` after it.
22
+ *
23
+ * @param name - Tag name
24
+ * @param closing - Match the closing form
25
+ * @returns The pattern source
26
+ */
27
+ function tagSource(name, closing) {
28
+ return `<${closing ? '\\s*/' : ''}[^<>]{0,40}?\\b${name}\\b[^<>]*>`;
29
+ }
30
+ /** Well-formed `<x>…</x>` blocks for the wrapper tags. */
31
+ const BLOCK_PATTERNS = ['function_calls', 'invoke'].map((name) => new RegExp(`${tagSource(name, false)}[\\s\\S]*?${tagSource(name, true)}`, 'gi'));
32
+ /** An opening wrapper tag with no close — the output was cut off mid-call. */
33
+ const UNCLOSED_PATTERN = new RegExp(`(?:${tagSource('function_calls', false)}|${tagSource('invoke', false)})[\\s\\S]*$`, 'i');
34
+ /** Any leftover lone tag. */
35
+ const LONE_TAG_PATTERN = new RegExp(ENVELOPE_TAGS.map((name) => `${tagSource(name, false)}|${tagSource(name, true)}`).join('|'), 'gi');
36
+ /**
37
+ * Whether a string contains something that looks like a tool-call envelope.
38
+ *
39
+ * @param raw - Candidate text
40
+ * @returns True when an `invoke` / `function_calls` tag is present
41
+ */
42
+ export function hasToolCallMarkup(raw) {
43
+ return new RegExp(`${tagSource('function_calls', false)}|${tagSource('invoke', false)}`, 'i').test(raw ?? '');
44
+ }
45
+ /**
46
+ * Remove tool-call markup from an agent's text response.
47
+ *
48
+ * Fenced code blocks (``` … ```) are passed through untouched: markup
49
+ * inside them is an example the agent meant to show.
50
+ *
51
+ * @param raw - The agent's text
52
+ * @returns The cleaned text and whether anything was removed
53
+ *
54
+ * @example
55
+ * stripToolCallMarkup('Working on it.\n<invoke name="Bash">…</invoke>')
56
+ * // → { text: 'Working on it.', stripped: true }
57
+ */
58
+ export function stripToolCallMarkup(raw) {
59
+ const input = raw ?? '';
60
+ if (!input)
61
+ return { text: '', stripped: false };
62
+ // Split on fences so the segments at odd indexes are fenced code.
63
+ const segments = input.split(/(```[\s\S]*?```)/g);
64
+ const cleaned = segments
65
+ .map((segment, i) => {
66
+ if (i % 2 === 1)
67
+ return segment; // fenced code — leave alone
68
+ let out = segment;
69
+ for (const pattern of BLOCK_PATTERNS)
70
+ out = out.replace(pattern, '');
71
+ out = out.replace(UNCLOSED_PATTERN, '');
72
+ return out.replace(LONE_TAG_PATTERN, '');
73
+ })
74
+ .join('');
75
+ const text = cleaned
76
+ .split('\n')
77
+ .map((line) => line.replace(/[ \t]+$/, ''))
78
+ .join('\n')
79
+ .replace(/\n{3,}/g, '\n\n')
80
+ .trim();
81
+ return { text, stripped: text !== input.trim() };
82
+ }
83
+ //# sourceMappingURL=tool-call-markup.utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-call-markup.utils.js","sourceRoot":"","sources":["../../../../../backend/src/utils/tool-call-markup.utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crewly",
3
- "version": "1.20.30",
3
+ "version": "1.20.31",
4
4
  "type": "module",
5
5
  "description": "Multi-agent orchestration platform for AI coding teams — coordinates Claude Code, Gemini CLI, and Codex agents with a real-time web dashboard",
6
6
  "workspaces": [