@a1hvdy/cc-openclaw 0.9.0 → 0.9.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 (227) hide show
  1. package/dist/scripts/bench/ab-harness.d.ts +58 -0
  2. package/dist/scripts/bench/ab-harness.d.ts.map +1 -0
  3. package/dist/scripts/bench/ab-harness.js +78 -0
  4. package/dist/scripts/bench/ab-harness.js.map +1 -0
  5. package/dist/src/channels/adapter.d.ts.map +1 -0
  6. package/dist/src/channels/telegram/completion-summary.d.ts.map +1 -0
  7. package/dist/src/channels/telegram/error-renderer.d.ts.map +1 -0
  8. package/dist/src/channels/telegram/event-reducer.d.ts.map +1 -0
  9. package/dist/src/channels/telegram/index.d.ts.map +1 -0
  10. package/dist/src/channels/telegram/injector.d.ts.map +1 -0
  11. package/dist/src/channels/telegram/live-card.d.ts.map +1 -0
  12. package/dist/src/channels/telegram/state-machine.d.ts.map +1 -0
  13. package/dist/src/channels/telegram/tool-tracker.d.ts.map +1 -0
  14. package/dist/src/command-router/cc-handler.d.ts.map +1 -0
  15. package/dist/src/command-router/index.d.ts.map +1 -0
  16. package/dist/src/constants.d.ts.map +1 -0
  17. package/dist/src/council/consensus.d.ts.map +1 -0
  18. package/dist/src/council/council.d.ts.map +1 -0
  19. package/dist/src/council/index.d.ts.map +1 -0
  20. package/dist/src/engines/base-oneshot-session.d.ts.map +1 -0
  21. package/dist/src/engines/index.d.ts.map +1 -0
  22. package/dist/src/engines/persistent-codex-session.d.ts.map +1 -0
  23. package/dist/src/engines/persistent-cursor-session.d.ts.map +1 -0
  24. package/dist/src/engines/persistent-custom-session.d.ts.map +1 -0
  25. package/dist/src/engines/persistent-gemini-session.d.ts.map +1 -0
  26. package/dist/src/engines/persistent-session.d.ts.map +1 -0
  27. package/dist/src/health/handler.d.ts.map +1 -0
  28. package/dist/src/health/index.d.ts.map +1 -0
  29. package/dist/src/index.d.ts.map +1 -0
  30. package/dist/src/lib/auto-recovery.d.ts.map +1 -0
  31. package/dist/src/lib/cache-parity.d.ts.map +1 -0
  32. package/dist/src/lib/circuit-breaker.d.ts.map +1 -0
  33. package/dist/src/lib/config.d.ts.map +1 -0
  34. package/dist/src/lib/debug-tap.d.ts.map +1 -0
  35. package/dist/src/lib/drift-detector.d.ts.map +1 -0
  36. package/dist/src/lib/error-formatter.d.ts.map +1 -0
  37. package/dist/src/lib/heartbeat-workaround.d.ts.map +1 -0
  38. package/dist/src/lib/index.d.ts.map +1 -0
  39. package/dist/src/lib/register-guard.d.ts.map +1 -0
  40. package/dist/src/lib/req-shape-log.d.ts +31 -0
  41. package/dist/src/lib/req-shape-log.js +106 -0
  42. package/dist/src/lib/req-shape-log.js.map +1 -0
  43. package/dist/src/lib/route-flag.d.ts +49 -0
  44. package/dist/src/lib/route-flag.d.ts.map +1 -0
  45. package/dist/src/lib/route-flag.js +52 -0
  46. package/dist/src/lib/route-flag.js.map +1 -0
  47. package/dist/src/lib/sysprompt-strip.d.ts.map +1 -0
  48. package/dist/src/lib/telemetry.d.ts.map +1 -0
  49. package/dist/src/lib/test-mode.d.ts.map +1 -0
  50. package/dist/src/lib/vendor-paths.d.ts.map +1 -0
  51. package/dist/src/logger.d.ts.map +1 -0
  52. package/dist/src/mcp/bridge.d.ts.map +1 -0
  53. package/dist/src/mcp/index.d.ts.map +1 -0
  54. package/dist/src/models.d.ts.map +1 -0
  55. package/dist/src/openai-compat/cli-stream-parser.d.ts.map +1 -0
  56. package/dist/src/openai-compat/index.d.ts.map +1 -0
  57. package/dist/src/openai-compat/message-extractor.js +31 -3
  58. package/dist/src/openai-compat/message-extractor.js.map +1 -1
  59. package/dist/src/openai-compat/openai-compat.d.ts.map +1 -0
  60. package/dist/src/openai-compat/openai-compat.js +6 -0
  61. package/dist/src/openai-compat/openai-compat.js.map +1 -1
  62. package/dist/src/openai-compat/skill-resolver.d.ts.map +1 -0
  63. package/dist/src/openai-compat/sse-translator.d.ts.map +1 -0
  64. package/dist/src/proxy/anthropic-adapter.d.ts.map +1 -0
  65. package/dist/src/proxy/handler.d.ts.map +1 -0
  66. package/dist/src/proxy/index.d.ts.map +1 -0
  67. package/dist/src/proxy/schema-cleaner.d.ts.map +1 -0
  68. package/dist/src/proxy/thought-cache.d.ts.map +1 -0
  69. package/dist/src/session/embedded-server.d.ts.map +1 -0
  70. package/dist/src/session/inbox-manager.d.ts.map +1 -0
  71. package/dist/src/session/index.d.ts.map +1 -0
  72. package/dist/src/session/session-manager.d.ts.map +1 -0
  73. package/dist/src/session-bootstrap/cwd-patch.d.ts.map +1 -0
  74. package/dist/src/session-bootstrap/index.d.ts.map +1 -0
  75. package/dist/src/session-bootstrap/sysprompt-strip.d.ts.map +1 -0
  76. package/dist/src/session-bootstrap/think-conflict-resolver.d.ts.map +1 -0
  77. package/dist/src/types.d.ts.map +1 -0
  78. package/dist/src/validation.d.ts.map +1 -0
  79. package/dist/tests/_helpers/subprocess-mock.d.ts +35 -0
  80. package/dist/tests/_helpers/subprocess-mock.d.ts.map +1 -0
  81. package/dist/tests/_helpers/subprocess-mock.js +136 -0
  82. package/dist/tests/_helpers/subprocess-mock.js.map +1 -0
  83. package/dist/tests/auto-recovery.test.d.ts +2 -0
  84. package/dist/tests/auto-recovery.test.d.ts.map +1 -0
  85. package/dist/tests/auto-recovery.test.js +189 -0
  86. package/dist/tests/auto-recovery.test.js.map +1 -0
  87. package/dist/tests/bench-harness.test.d.ts +2 -0
  88. package/dist/tests/bench-harness.test.d.ts.map +1 -0
  89. package/dist/tests/bench-harness.test.js +21 -0
  90. package/dist/tests/bench-harness.test.js.map +1 -0
  91. package/dist/tests/cache-parity.test.d.ts +2 -0
  92. package/dist/tests/cache-parity.test.d.ts.map +1 -0
  93. package/dist/tests/cache-parity.test.js +401 -0
  94. package/dist/tests/cache-parity.test.js.map +1 -0
  95. package/dist/tests/command-router.test.d.ts +2 -0
  96. package/dist/tests/command-router.test.d.ts.map +1 -0
  97. package/dist/tests/command-router.test.js +60 -0
  98. package/dist/tests/command-router.test.js.map +1 -0
  99. package/dist/tests/council.test.d.ts +2 -0
  100. package/dist/tests/council.test.d.ts.map +1 -0
  101. package/dist/tests/council.test.js +20 -0
  102. package/dist/tests/council.test.js.map +1 -0
  103. package/dist/tests/drift-detector.test.d.ts +2 -0
  104. package/dist/tests/drift-detector.test.d.ts.map +1 -0
  105. package/dist/tests/drift-detector.test.js +268 -0
  106. package/dist/tests/drift-detector.test.js.map +1 -0
  107. package/dist/tests/eager-bootstrap-gating.test.d.ts +9 -0
  108. package/dist/tests/eager-bootstrap-gating.test.d.ts.map +1 -0
  109. package/dist/tests/eager-bootstrap-gating.test.js +97 -0
  110. package/dist/tests/eager-bootstrap-gating.test.js.map +1 -0
  111. package/dist/tests/engines.test.d.ts +2 -0
  112. package/dist/tests/engines.test.d.ts.map +1 -0
  113. package/dist/tests/engines.test.js +8 -0
  114. package/dist/tests/engines.test.js.map +1 -0
  115. package/dist/tests/error-formatter.test.d.ts +2 -0
  116. package/dist/tests/error-formatter.test.d.ts.map +1 -0
  117. package/dist/tests/error-formatter.test.js +220 -0
  118. package/dist/tests/error-formatter.test.js.map +1 -0
  119. package/dist/tests/health.test.d.ts +2 -0
  120. package/dist/tests/health.test.d.ts.map +1 -0
  121. package/dist/tests/health.test.js +110 -0
  122. package/dist/tests/health.test.js.map +1 -0
  123. package/dist/tests/heartbeat-workaround.test.d.ts +2 -0
  124. package/dist/tests/heartbeat-workaround.test.d.ts.map +1 -0
  125. package/dist/tests/heartbeat-workaround.test.js +90 -0
  126. package/dist/tests/heartbeat-workaround.test.js.map +1 -0
  127. package/dist/tests/index.test.d.ts +2 -0
  128. package/dist/tests/index.test.d.ts.map +1 -0
  129. package/dist/tests/index.test.js +7 -0
  130. package/dist/tests/index.test.js.map +1 -0
  131. package/dist/tests/lib-sysprompt-strip.test.d.ts +2 -0
  132. package/dist/tests/lib-sysprompt-strip.test.d.ts.map +1 -0
  133. package/dist/tests/lib-sysprompt-strip.test.js +145 -0
  134. package/dist/tests/lib-sysprompt-strip.test.js.map +1 -0
  135. package/dist/tests/listener-activation.test.d.ts +2 -0
  136. package/dist/tests/listener-activation.test.d.ts.map +1 -0
  137. package/dist/tests/listener-activation.test.js +87 -0
  138. package/dist/tests/listener-activation.test.js.map +1 -0
  139. package/dist/tests/mcp-bridge.test.d.ts +2 -0
  140. package/dist/tests/mcp-bridge.test.d.ts.map +1 -0
  141. package/dist/tests/mcp-bridge.test.js +137 -0
  142. package/dist/tests/mcp-bridge.test.js.map +1 -0
  143. package/dist/tests/openai-compat.test.d.ts +2 -0
  144. package/dist/tests/openai-compat.test.d.ts.map +1 -0
  145. package/dist/tests/openai-compat.test.js +8 -0
  146. package/dist/tests/openai-compat.test.js.map +1 -0
  147. package/dist/tests/proxy-heartbeat-integration.test.d.ts +15 -0
  148. package/dist/tests/proxy-heartbeat-integration.test.d.ts.map +1 -0
  149. package/dist/tests/proxy-heartbeat-integration.test.js +122 -0
  150. package/dist/tests/proxy-heartbeat-integration.test.js.map +1 -0
  151. package/dist/tests/proxy.test.d.ts +2 -0
  152. package/dist/tests/proxy.test.d.ts.map +1 -0
  153. package/dist/tests/proxy.test.js +8 -0
  154. package/dist/tests/proxy.test.js.map +1 -0
  155. package/dist/tests/register-guard-stacking.test.d.ts +2 -0
  156. package/dist/tests/register-guard-stacking.test.d.ts.map +1 -0
  157. package/dist/tests/register-guard-stacking.test.js +61 -0
  158. package/dist/tests/register-guard-stacking.test.js.map +1 -0
  159. package/dist/tests/register-guard.test.d.ts +2 -0
  160. package/dist/tests/register-guard.test.d.ts.map +1 -0
  161. package/dist/tests/register-guard.test.js +129 -0
  162. package/dist/tests/register-guard.test.js.map +1 -0
  163. package/dist/tests/route-flag-rollback.test.d.ts +2 -0
  164. package/dist/tests/route-flag-rollback.test.d.ts.map +1 -0
  165. package/dist/tests/route-flag-rollback.test.js +70 -0
  166. package/dist/tests/route-flag-rollback.test.js.map +1 -0
  167. package/dist/tests/route-flag.test.d.ts +2 -0
  168. package/dist/tests/route-flag.test.d.ts.map +1 -0
  169. package/dist/tests/route-flag.test.js +101 -0
  170. package/dist/tests/route-flag.test.js.map +1 -0
  171. package/dist/tests/session-bootstrap.test.d.ts +2 -0
  172. package/dist/tests/session-bootstrap.test.d.ts.map +1 -0
  173. package/dist/tests/session-bootstrap.test.js +183 -0
  174. package/dist/tests/session-bootstrap.test.js.map +1 -0
  175. package/dist/tests/session.test.d.ts +2 -0
  176. package/dist/tests/session.test.d.ts.map +1 -0
  177. package/dist/tests/session.test.js +17 -0
  178. package/dist/tests/session.test.js.map +1 -0
  179. package/dist/tests/state-machine.test.d.ts +2 -0
  180. package/dist/tests/state-machine.test.d.ts.map +1 -0
  181. package/dist/tests/state-machine.test.js +133 -0
  182. package/dist/tests/state-machine.test.js.map +1 -0
  183. package/dist/tests/streaming/cli-stream-parser.test.d.ts +2 -0
  184. package/dist/tests/streaming/cli-stream-parser.test.d.ts.map +1 -0
  185. package/dist/tests/streaming/cli-stream-parser.test.js +233 -0
  186. package/dist/tests/streaming/cli-stream-parser.test.js.map +1 -0
  187. package/dist/tests/streaming/feature-flag.test.d.ts +14 -0
  188. package/dist/tests/streaming/feature-flag.test.d.ts.map +1 -0
  189. package/dist/tests/streaming/feature-flag.test.js +163 -0
  190. package/dist/tests/streaming/feature-flag.test.js.map +1 -0
  191. package/dist/tests/streaming/no-tools-prompt.test.d.ts +17 -0
  192. package/dist/tests/streaming/no-tools-prompt.test.d.ts.map +1 -0
  193. package/dist/tests/streaming/no-tools-prompt.test.js +229 -0
  194. package/dist/tests/streaming/no-tools-prompt.test.js.map +1 -0
  195. package/dist/tests/streaming/skill-plus-tools.test.d.ts +14 -0
  196. package/dist/tests/streaming/skill-plus-tools.test.d.ts.map +1 -0
  197. package/dist/tests/streaming/skill-plus-tools.test.js +234 -0
  198. package/dist/tests/streaming/skill-plus-tools.test.js.map +1 -0
  199. package/dist/tests/streaming/sse-translator.test.d.ts +2 -0
  200. package/dist/tests/streaming/sse-translator.test.d.ts.map +1 -0
  201. package/dist/tests/streaming/sse-translator.test.js +227 -0
  202. package/dist/tests/streaming/sse-translator.test.js.map +1 -0
  203. package/dist/tests/streaming/tool-result-roundtrip.test.d.ts +11 -0
  204. package/dist/tests/streaming/tool-result-roundtrip.test.d.ts.map +1 -0
  205. package/dist/tests/streaming/tool-result-roundtrip.test.js +215 -0
  206. package/dist/tests/streaming/tool-result-roundtrip.test.js.map +1 -0
  207. package/dist/tests/streaming/tool-use-translation.test.d.ts +10 -0
  208. package/dist/tests/streaming/tool-use-translation.test.d.ts.map +1 -0
  209. package/dist/tests/streaming/tool-use-translation.test.js +251 -0
  210. package/dist/tests/streaming/tool-use-translation.test.js.map +1 -0
  211. package/dist/tests/telegram-bridge.test.d.ts +2 -0
  212. package/dist/tests/telegram-bridge.test.d.ts.map +1 -0
  213. package/dist/tests/telegram-bridge.test.js +17 -0
  214. package/dist/tests/telegram-bridge.test.js.map +1 -0
  215. package/dist/tests/telegram-injector.test.d.ts +2 -0
  216. package/dist/tests/telegram-injector.test.d.ts.map +1 -0
  217. package/dist/tests/telegram-injector.test.js +74 -0
  218. package/dist/tests/telegram-injector.test.js.map +1 -0
  219. package/dist/tests/telemetry.test.d.ts +2 -0
  220. package/dist/tests/telemetry.test.d.ts.map +1 -0
  221. package/dist/tests/telemetry.test.js +405 -0
  222. package/dist/tests/telemetry.test.js.map +1 -0
  223. package/dist/tests/test-mode.test.d.ts +2 -0
  224. package/dist/tests/test-mode.test.d.ts.map +1 -0
  225. package/dist/tests/test-mode.test.js +39 -0
  226. package/dist/tests/test-mode.test.js.map +1 -0
  227. package/package.json +1 -1
@@ -0,0 +1,234 @@
1
+ // phase: 4 | pillar: 0.5 | agent: P05.B
2
+ /**
3
+ * R6 coexist test: verifies that skill auto-inline AND tools[] forwarding
4
+ * work simultaneously on the same request.
5
+ *
6
+ * Asserts:
7
+ * a) SKILL.md body is present in the user message sent to subprocess
8
+ * b) tools[] array is forwarded to the session (present in sessionConfig)
9
+ *
10
+ * Uses a temporary skills directory so the test is hermetic.
11
+ * Does NOT spawn a real subprocess — verifies the message extraction and
12
+ * session config construction layer (extractUserMessage + buildSessionSystemPrompt).
13
+ */
14
+ import { describe, expect, it, beforeEach, afterEach } from 'vitest';
15
+ import * as path from 'node:path';
16
+ import * as os from 'node:os';
17
+ import * as fs from 'node:fs';
18
+ import { extractUserMessage, buildSessionSystemPrompt, buildToolPromptBlock, } from '../../src/openai-compat/openai-compat.js';
19
+ import { maybeInlineSkill } from '../../src/openai-compat/skill-resolver.js';
20
+ // ─── Tool fixtures ─────────────────────────────────────────────────────────
21
+ const READ_TOOL = {
22
+ type: 'function',
23
+ function: {
24
+ name: 'Read',
25
+ description: 'Read a file from disk',
26
+ parameters: {
27
+ type: 'object',
28
+ properties: { file_path: { type: 'string', description: 'Path to file' } },
29
+ required: ['file_path'],
30
+ },
31
+ },
32
+ };
33
+ const WEBFETCH_TOOL = {
34
+ type: 'function',
35
+ function: {
36
+ name: 'WebFetch',
37
+ description: 'Fetch a URL',
38
+ parameters: {
39
+ type: 'object',
40
+ properties: { url: { type: 'string', description: 'URL to fetch' } },
41
+ required: ['url'],
42
+ },
43
+ },
44
+ };
45
+ // ─── Skill fixture setup ───────────────────────────────────────────────────
46
+ let tmpSkillsDir;
47
+ const SEARCH_SKILL_BODY = [
48
+ '---',
49
+ 'name: search',
50
+ '---',
51
+ '# Deep Research Skill',
52
+ '',
53
+ 'You are a deep research assistant. Use WebFetch and WebSearch to gather',
54
+ 'information, then synthesize findings into a scored research report.',
55
+ '',
56
+ '## Steps',
57
+ '1. Identify key search terms',
58
+ '2. Fetch relevant sources via WebFetch',
59
+ '3. Synthesize and score results',
60
+ ].join('\n');
61
+ beforeEach(() => {
62
+ tmpSkillsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cc-openclaw-r6-'));
63
+ const searchDir = path.join(tmpSkillsDir, 'deep-research');
64
+ fs.mkdirSync(searchDir, { recursive: true });
65
+ fs.writeFileSync(path.join(searchDir, 'SKILL.md'), SEARCH_SKILL_BODY);
66
+ process.env.OPENCLAW_WORKSPACE_SKILLS_DIR = tmpSkillsDir;
67
+ });
68
+ afterEach(() => {
69
+ delete process.env.OPENCLAW_WORKSPACE_SKILLS_DIR;
70
+ fs.rmSync(tmpSkillsDir, { recursive: true, force: true });
71
+ });
72
+ // ─── R6.a: SKILL.md body present in user message ──────────────────────────
73
+ describe('skill-plus-tools — R6.a: skill body inlined into user message', () => {
74
+ it('maybeInlineSkill returns skill body for /search command', () => {
75
+ const result = maybeInlineSkill('/search latest openclaw release');
76
+ expect(result).not.toBeNull();
77
+ expect(result).toContain('Deep Research Skill');
78
+ });
79
+ it('inlined message contains the skill body AND the user args', () => {
80
+ const result = maybeInlineSkill('/search openclaw streaming pipeline');
81
+ expect(result).not.toBeNull();
82
+ expect(result).toContain('Deep Research Skill');
83
+ expect(result).toContain('openclaw streaming pipeline');
84
+ });
85
+ it('extractUserMessage inlines skill for /search user message', () => {
86
+ const messages = [
87
+ { role: 'user', content: '/search foo bar' },
88
+ ];
89
+ const extracted = extractUserMessage(messages);
90
+ expect(extracted.userMessage).toContain('Deep Research Skill');
91
+ expect(extracted.userMessage).toContain('foo bar');
92
+ });
93
+ it('skill body includes tool usage instructions from SKILL.md', () => {
94
+ const result = maybeInlineSkill('/search test query');
95
+ expect(result).toContain('WebFetch');
96
+ expect(result).toContain('research');
97
+ });
98
+ it('skill inline works with system message present', () => {
99
+ const messages = [
100
+ { role: 'system', content: 'You are a helpful assistant.' },
101
+ { role: 'user', content: '/search latest news' },
102
+ ];
103
+ const extracted = extractUserMessage(messages);
104
+ expect(extracted.userMessage).toContain('Deep Research Skill');
105
+ expect(extracted.systemPrompt).toBe('You are a helpful assistant.');
106
+ });
107
+ });
108
+ // ─── R6.b: tools[] array forwarded to sessionConfig ───────────────────────
109
+ describe('skill-plus-tools — R6.b: tools array forwarded', () => {
110
+ it('buildSessionSystemPrompt includes all tool names when tools provided', () => {
111
+ const prompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL], undefined);
112
+ expect(prompt).toContain('Read');
113
+ expect(prompt).toContain('WebFetch');
114
+ });
115
+ it('buildToolPromptBlock includes both tool definitions', () => {
116
+ const block = buildToolPromptBlock([READ_TOOL, WEBFETCH_TOOL]);
117
+ expect(block).toContain('Read');
118
+ expect(block).toContain('Read a file from disk');
119
+ expect(block).toContain('WebFetch');
120
+ expect(block).toContain('Fetch a URL');
121
+ });
122
+ it('tools are forwarded independently of skill inline (tools in sessionConfig, skill in userMessage)', () => {
123
+ const messages = [
124
+ { role: 'user', content: '/search foo' },
125
+ ];
126
+ const extracted = extractUserMessage(messages);
127
+ // User message has the skill body
128
+ expect(extracted.userMessage).toContain('Deep Research Skill');
129
+ // Tools are in the session system prompt (separate from user message)
130
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL], undefined);
131
+ expect(sessionPrompt).toContain('Read');
132
+ expect(sessionPrompt).toContain('WebFetch');
133
+ });
134
+ });
135
+ // ─── R6: coexist — both simultaneously ────────────────────────────────────
136
+ describe('skill-plus-tools — R6 coexist: skill body AND tools forwarded together', () => {
137
+ it('extractUserMessage skill inline + buildSessionSystemPrompt tools: both present', () => {
138
+ const messages = [
139
+ { role: 'user', content: '/search openclaw release notes' },
140
+ ];
141
+ const extracted = extractUserMessage(messages);
142
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL], undefined);
143
+ // R6.a: skill body in user message
144
+ expect(extracted.userMessage).toContain('Deep Research Skill');
145
+ expect(extracted.userMessage).toContain('openclaw release notes');
146
+ // R6.b: tools in session prompt
147
+ expect(sessionPrompt).toContain('Read');
148
+ expect(sessionPrompt).toContain('WebFetch');
149
+ expect(sessionPrompt).toContain('<available_tools>');
150
+ });
151
+ it('no "you have no tools" sentinel in either the user message or session prompt', () => {
152
+ const messages = [
153
+ { role: 'user', content: '/search test query' },
154
+ ];
155
+ const extracted = extractUserMessage(messages);
156
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL], undefined);
157
+ expect(extracted.userMessage.toLowerCase()).not.toContain('you have no tools');
158
+ expect(sessionPrompt.toLowerCase()).not.toContain('you have no tools');
159
+ });
160
+ it('skill args from /search are preserved alongside skill body', () => {
161
+ const query = 'latest openclaw streaming pipeline release 2026';
162
+ const result = maybeInlineSkill(`/search ${query}`);
163
+ expect(result).not.toBeNull();
164
+ expect(result).toContain(query);
165
+ expect(result).toContain('Deep Research Skill');
166
+ });
167
+ it('both Read and WebFetch tool descriptions appear in session system prompt', () => {
168
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL], undefined);
169
+ expect(sessionPrompt).toContain('Read a file from disk');
170
+ expect(sessionPrompt).toContain('Fetch a URL');
171
+ });
172
+ it('tools fingerprint varies between [Read] and [Read, WebFetch] (different sessions)', async () => {
173
+ // This verifies R6 does not break session key isolation
174
+ const { resolveSessionKey } = await import('../../src/openai-compat/openai-compat.js');
175
+ const reqA = {
176
+ messages: [{ role: 'user', content: '/search foo' }],
177
+ tools: [READ_TOOL],
178
+ };
179
+ const reqB = {
180
+ messages: [{ role: 'user', content: '/search foo' }],
181
+ tools: [READ_TOOL, WEBFETCH_TOOL],
182
+ };
183
+ const keyA = resolveSessionKey(reqA, {});
184
+ const keyB = resolveSessionKey(reqB, {});
185
+ expect(keyA).not.toBe(keyB);
186
+ });
187
+ });
188
+ // ─── Edge cases ────────────────────────────────────────────────────────────
189
+ describe('skill-plus-tools — edge cases', () => {
190
+ it('unknown slash command is passed through unchanged (no skill found)', () => {
191
+ const result = maybeInlineSkill('/nonexistent-command foo');
192
+ expect(result).toBeNull();
193
+ // extractUserMessage should return the raw text
194
+ const messages = [
195
+ { role: 'user', content: '/nonexistent-command foo' },
196
+ ];
197
+ const extracted = extractUserMessage(messages);
198
+ expect(extracted.userMessage).toBe('/nonexistent-command foo');
199
+ });
200
+ it('tools=[] with skill inline: no <available_tools> block in session prompt', () => {
201
+ const sessionPrompt = buildSessionSystemPrompt([], undefined);
202
+ // Preamble text mentions "<available_tools>" as prose; assert on the
203
+ // closing tag, only present when an actual block is rendered.
204
+ expect(sessionPrompt).not.toContain('</available_tools>');
205
+ // skill inline is in user message, not session prompt — remains independent
206
+ const result = maybeInlineSkill('/search foo');
207
+ expect(result).toContain('Deep Research Skill');
208
+ });
209
+ it('non-slash user message with tools: no skill inline, tools forwarded', () => {
210
+ const messages = [
211
+ { role: 'user', content: 'What is the capital of France?' },
212
+ ];
213
+ const extracted = extractUserMessage(messages);
214
+ expect(extracted.userMessage).toBe('What is the capital of France?');
215
+ expect(extracted.userMessage).not.toContain('Deep Research Skill');
216
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL], undefined);
217
+ expect(sessionPrompt).toContain('Read');
218
+ });
219
+ it('skill with multiple tools: all tools appear in session prompt', () => {
220
+ const BASH_TOOL = {
221
+ type: 'function',
222
+ function: {
223
+ name: 'Bash',
224
+ description: 'Execute shell commands',
225
+ parameters: { type: 'object', properties: { command: { type: 'string' } }, required: ['command'] },
226
+ },
227
+ };
228
+ const sessionPrompt = buildSessionSystemPrompt([READ_TOOL, WEBFETCH_TOOL, BASH_TOOL], undefined);
229
+ expect(sessionPrompt).toContain('Read');
230
+ expect(sessionPrompt).toContain('WebFetch');
231
+ expect(sessionPrompt).toContain('Bash');
232
+ });
233
+ });
234
+ //# sourceMappingURL=skill-plus-tools.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skill-plus-tools.test.js","sourceRoot":"","sources":["../../../tests/streaming/skill-plus-tools.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sse-translator.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-translator.test.d.ts","sourceRoot":"","sources":["../../../tests/streaming/sse-translator.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { createSseTranslator } from '../../src/openai-compat/sse-translator.js';
3
+ function parseChunk(sse) {
4
+ expect(sse.startsWith('data: ')).toBe(true);
5
+ expect(sse.endsWith('\n\n')).toBe(true);
6
+ return JSON.parse(sse.slice('data: '.length, -2));
7
+ }
8
+ const TX_PARAMS = { completionId: 'chatcmpl-test', model: 'claude-opus-4-7' };
9
+ describe('sse-translator — text response', () => {
10
+ it('emits content deltas for text_delta events', () => {
11
+ const tx = createSseTranslator(TX_PARAMS);
12
+ const events = [
13
+ { type: 'message_start', message: { id: 'm', model: 'claude-opus-4-7', usage: { input_tokens: 10 } } },
14
+ { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } },
15
+ { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'Hi! ' } },
16
+ { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'How can I help?' } },
17
+ { type: 'content_block_stop', index: 0 },
18
+ { type: 'message_delta', delta: { stop_reason: 'end_turn' } },
19
+ { type: 'message_stop' },
20
+ ];
21
+ const chunks = events.flatMap((e) => tx.translate(e));
22
+ const parsed = chunks.map(parseChunk);
23
+ expect(parsed.map((p) => p.choices[0].delta)).toEqual([
24
+ { content: 'Hi! ' },
25
+ { content: 'How can I help?' },
26
+ {},
27
+ ]);
28
+ expect(parsed[parsed.length - 1].choices[0].finish_reason).toBe('stop');
29
+ });
30
+ it('emits no chunks for content_block_start (text), message_start, content_block_stop, message_stop', () => {
31
+ const tx = createSseTranslator(TX_PARAMS);
32
+ expect(tx.translate({ type: 'message_start', message: { id: 'x', model: 'claude-opus-4-7' } })).toEqual([]);
33
+ expect(tx.translate({ type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } })).toEqual([]);
34
+ expect(tx.translate({ type: 'content_block_stop', index: 0 })).toEqual([]);
35
+ expect(tx.translate({ type: 'message_stop' })).toEqual([]);
36
+ });
37
+ });
38
+ describe('sse-translator — tool_use', () => {
39
+ it('emits tool_calls start chunk on content_block_start (tool_use)', () => {
40
+ const tx = createSseTranslator(TX_PARAMS);
41
+ const chunks = tx.translate({
42
+ type: 'content_block_start',
43
+ index: 0,
44
+ content_block: { type: 'tool_use', id: 'toolu_x', name: 'Bash', input: {} },
45
+ });
46
+ expect(chunks).toHaveLength(1);
47
+ const p = parseChunk(chunks[0]);
48
+ expect(p.choices[0].delta).toEqual({
49
+ tool_calls: [{ index: 0, id: 'toolu_x', type: 'function', function: { name: 'Bash', arguments: '' } }],
50
+ });
51
+ });
52
+ it('emits argument deltas for input_json_delta tied to the tool_use index', () => {
53
+ const tx = createSseTranslator(TX_PARAMS);
54
+ tx.translate({
55
+ type: 'content_block_start',
56
+ index: 0,
57
+ content_block: { type: 'tool_use', id: 'toolu_x', name: 'Bash', input: {} },
58
+ });
59
+ const chunks = tx.translate({
60
+ type: 'content_block_delta',
61
+ index: 0,
62
+ delta: { type: 'input_json_delta', partial_json: '{"command":"ls"}' },
63
+ });
64
+ expect(chunks).toHaveLength(1);
65
+ const p = parseChunk(chunks[0]);
66
+ expect(p.choices[0].delta).toEqual({
67
+ tool_calls: [{ index: 0, function: { arguments: '{"command":"ls"}' } }],
68
+ });
69
+ });
70
+ it('emits parallel tool_calls with separate indices', () => {
71
+ const tx = createSseTranslator(TX_PARAMS);
72
+ const events = [
73
+ { type: 'content_block_start', index: 0, content_block: { type: 'tool_use', id: 'toolu_a', name: 'Bash', input: {} } },
74
+ { type: 'content_block_delta', index: 0, delta: { type: 'input_json_delta', partial_json: '{"a":1}' } },
75
+ { type: 'content_block_start', index: 1, content_block: { type: 'tool_use', id: 'toolu_b', name: 'Read', input: {} } },
76
+ { type: 'content_block_delta', index: 1, delta: { type: 'input_json_delta', partial_json: '{"b":2}' } },
77
+ ];
78
+ const chunks = events.flatMap((e) => tx.translate(e)).map(parseChunk);
79
+ const toolCallIndices = chunks.map((p) => {
80
+ const tc = p.choices[0].delta.tool_calls;
81
+ return tc?.[0]?.index;
82
+ });
83
+ expect(toolCallIndices).toEqual([0, 0, 1, 1]);
84
+ });
85
+ it('drops input_json_delta when no preceding content_block_start arrived', () => {
86
+ const tx = createSseTranslator(TX_PARAMS);
87
+ const chunks = tx.translate({
88
+ type: 'content_block_delta',
89
+ index: 0,
90
+ delta: { type: 'input_json_delta', partial_json: '{}' },
91
+ });
92
+ expect(chunks).toEqual([]);
93
+ });
94
+ it('mixes text + tool_use blocks correctly (text uses content delta, tool_use uses tool_calls)', () => {
95
+ const tx = createSseTranslator(TX_PARAMS);
96
+ const events = [
97
+ { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } },
98
+ { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'Running...' } },
99
+ { type: 'content_block_start', index: 1, content_block: { type: 'tool_use', id: 'toolu_x', name: 'Bash', input: {} } },
100
+ { type: 'content_block_delta', index: 1, delta: { type: 'input_json_delta', partial_json: '{"command":"pwd"}' } },
101
+ ];
102
+ const chunks = events.flatMap((e) => tx.translate(e)).map(parseChunk);
103
+ expect(chunks[0].choices[0].delta).toEqual({ content: 'Running...' });
104
+ expect(chunks[1].choices[0].delta).toMatchObject({ tool_calls: [{ index: 0, id: 'toolu_x' }] });
105
+ expect(chunks[2].choices[0].delta).toMatchObject({ tool_calls: [{ index: 0, function: { arguments: '{"command":"pwd"}' } }] });
106
+ });
107
+ });
108
+ describe('sse-translator — thinking blocks (skipped)', () => {
109
+ it('emits no chunks for thinking content_block_start', () => {
110
+ const tx = createSseTranslator(TX_PARAMS);
111
+ const chunks = tx.translate({
112
+ type: 'content_block_start',
113
+ index: 0,
114
+ content_block: { type: 'thinking', thinking: '', signature: '' },
115
+ });
116
+ expect(chunks).toEqual([]);
117
+ });
118
+ it('emits no chunks for thinking_delta or signature_delta', () => {
119
+ const tx = createSseTranslator(TX_PARAMS);
120
+ expect(tx.translate({ type: 'content_block_delta', index: 0, delta: { type: 'thinking_delta', thinking: 'pondering' } })).toEqual([]);
121
+ expect(tx.translate({ type: 'content_block_delta', index: 0, delta: { type: 'signature_delta', signature: 'xxx' } })).toEqual([]);
122
+ });
123
+ });
124
+ describe('sse-translator — finish_reason mapping', () => {
125
+ it('maps end_turn → stop', () => {
126
+ const tx = createSseTranslator(TX_PARAMS);
127
+ const chunks = tx.translate({ type: 'message_delta', delta: { stop_reason: 'end_turn' } });
128
+ expect(parseChunk(chunks[0]).choices[0].finish_reason).toBe('stop');
129
+ });
130
+ it('maps tool_use → tool_calls', () => {
131
+ const tx = createSseTranslator(TX_PARAMS);
132
+ const chunks = tx.translate({ type: 'message_delta', delta: { stop_reason: 'tool_use' } });
133
+ expect(parseChunk(chunks[0]).choices[0].finish_reason).toBe('tool_calls');
134
+ });
135
+ it('maps max_tokens → length', () => {
136
+ const tx = createSseTranslator(TX_PARAMS);
137
+ const chunks = tx.translate({ type: 'message_delta', delta: { stop_reason: 'max_tokens' } });
138
+ expect(parseChunk(chunks[0]).choices[0].finish_reason).toBe('length');
139
+ });
140
+ it('maps stop_sequence → stop', () => {
141
+ const tx = createSseTranslator(TX_PARAMS);
142
+ const chunks = tx.translate({ type: 'message_delta', delta: { stop_reason: 'stop_sequence' } });
143
+ expect(parseChunk(chunks[0]).choices[0].finish_reason).toBe('stop');
144
+ });
145
+ it('emits usage chunk when emitUsage:true and message_delta carries output_tokens', () => {
146
+ const tx = createSseTranslator({ ...TX_PARAMS, emitUsage: true });
147
+ tx.translate({ type: 'message_start', message: { id: 'm', model: 'claude-opus-4-7', usage: { input_tokens: 7 } } });
148
+ const chunks = tx.translate({ type: 'message_delta', delta: { stop_reason: 'end_turn' }, usage: { output_tokens: 11 } });
149
+ expect(chunks).toHaveLength(2);
150
+ const usage = JSON.parse(chunks[1].slice('data: '.length, -2));
151
+ expect(usage.usage).toEqual({ prompt_tokens: 7, completion_tokens: 11, total_tokens: 18 });
152
+ });
153
+ });
154
+ describe('sse-translator — error and envelope events', () => {
155
+ it('emits content with error info for error events', () => {
156
+ const tx = createSseTranslator(TX_PARAMS);
157
+ const chunks = tx.translate({ type: 'error', error: { type: 'overloaded_error', message: 'try later' } });
158
+ const p = parseChunk(chunks[0]);
159
+ expect(p.choices[0].delta.content).toContain('overloaded_error');
160
+ expect(p.choices[0].delta.content).toContain('try later');
161
+ expect(p.choices[0].finish_reason).toBe('stop');
162
+ });
163
+ it('emits content for parse_error events', () => {
164
+ const tx = createSseTranslator(TX_PARAMS);
165
+ const chunks = tx.translate({ type: 'parse_error', error: { type: 'json_parse', message: 'bad json' } });
166
+ expect(chunks).toHaveLength(1);
167
+ const p = parseChunk(chunks[0]);
168
+ expect(p.choices[0].delta.content).toContain('parse_error');
169
+ });
170
+ it.each([
171
+ ['system', { type: 'system', subtype: 'init', raw: {} }],
172
+ ['assistant', { type: 'assistant', message: { id: 'm', model: 'claude-opus-4-7' } }],
173
+ ['rate_limit_event', { type: 'rate_limit_event', rateLimitInfo: {} }],
174
+ ['result', { type: 'result', subtype: 'success', isError: false, raw: {} }],
175
+ ['unknown', { type: 'unknown', raw: {} }],
176
+ ])('skips %s envelope events', (_name, event) => {
177
+ const tx = createSseTranslator(TX_PARAMS);
178
+ expect(tx.translate(event)).toEqual([]);
179
+ });
180
+ });
181
+ describe('sse-translator — done()', () => {
182
+ it('emits exactly [DONE] sentinel', () => {
183
+ const tx = createSseTranslator(TX_PARAMS);
184
+ expect(tx.done()).toEqual(['data: [DONE]\n\n']);
185
+ });
186
+ });
187
+ describe('sse-translator — chunk format', () => {
188
+ it('every chunk starts with "data: " and ends with "\\n\\n"', () => {
189
+ const tx = createSseTranslator(TX_PARAMS);
190
+ const events = [
191
+ { type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } },
192
+ { type: 'content_block_delta', index: 0, delta: { type: 'text_delta', text: 'hi' } },
193
+ { type: 'message_delta', delta: { stop_reason: 'end_turn' } },
194
+ ];
195
+ for (const e of events) {
196
+ for (const chunk of tx.translate(e)) {
197
+ expect(chunk.startsWith('data: ')).toBe(true);
198
+ expect(chunk.endsWith('\n\n')).toBe(true);
199
+ }
200
+ }
201
+ for (const chunk of tx.done()) {
202
+ expect(chunk.startsWith('data: ')).toBe(true);
203
+ expect(chunk.endsWith('\n\n')).toBe(true);
204
+ }
205
+ });
206
+ it('every chunk includes id, object="chat.completion.chunk", model', () => {
207
+ const tx = createSseTranslator(TX_PARAMS);
208
+ const chunks = tx.translate({
209
+ type: 'content_block_delta',
210
+ index: 0,
211
+ delta: { type: 'text_delta', text: 'x' },
212
+ });
213
+ // Need to start the block first
214
+ const tx2 = createSseTranslator(TX_PARAMS);
215
+ tx2.translate({ type: 'content_block_start', index: 0, content_block: { type: 'text', text: '' } });
216
+ const chunks2 = tx2.translate({
217
+ type: 'content_block_delta',
218
+ index: 0,
219
+ delta: { type: 'text_delta', text: 'x' },
220
+ });
221
+ const p = parseChunk(chunks2[0]);
222
+ expect(p.id).toBe('chatcmpl-test');
223
+ expect(p.choices[0].delta.content).toBe('x');
224
+ void chunks; // first call also valid as text_delta doesn't need block_start
225
+ });
226
+ });
227
+ //# sourceMappingURL=sse-translator.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sse-translator.test.js","sourceRoot":"","sources":["../../../tests/streaming/sse-translator.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,mBAAmB,EAAE,MAAM,2CAA2C,CAAC;AAGhF,SAAS,UAAU,CAAC,GAAW;IAC7B,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,SAAS,GAAG,EAAE,YAAY,EAAE,eAAe,EAAE,KAAK,EAAE,iBAAiB,EAAE,CAAC;AAE9E,QAAQ,CAAC,gCAAgC,EAAE,GAAG,EAAE;IAC9C,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAkB;YAC5B,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,EAAE;YACtG,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;YACpF,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YACtF,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE;YACjG,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE;YACxC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE;YAC7D,EAAE,IAAI,EAAE,cAAc,EAAE;SACzB,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YACpD,EAAE,OAAO,EAAE,MAAM,EAAE;YACnB,EAAE,OAAO,EAAE,iBAAiB,EAAE;YAC9B,EAAE;SACH,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iGAAiG,EAAE,GAAG,EAAE;QACzG,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC5G,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACvH,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC3E,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACzC,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;SAC5E,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YACjC,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,CAAC;SACvG,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,GAAG,EAAE;QAC/E,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,EAAE,CAAC,SAAS,CAAC;YACX,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE;SAC5E,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,kBAAkB,EAAE;SACtE,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YACjC,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,kBAAkB,EAAE,EAAE,CAAC;SACxE,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAkB;YAC5B,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACtH,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE;YACvG,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACtH,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE;SACxG,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACtE,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;YACvC,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAkD,CAAC;YACjF,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,eAAe,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,IAAI,EAAE;SACxD,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4FAA4F,EAAE,GAAG,EAAE;QACpG,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAkB;YAC5B,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;YACpF,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE;YAC5F,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACtH,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,YAAY,EAAE,mBAAmB,EAAE,EAAE;SAClH,CAAC;QACF,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QACtE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;QACtE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC;QAChG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,EAAE,mBAAmB,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;IACjI,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IAC1D,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,aAAa,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;SACjE,CAAC,CAAC;QACH,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CACJ,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,QAAQ,EAAE,WAAW,EAAE,EAAE,CAAC,CAClH,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACd,MAAM,CACJ,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAC,CAC9G,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,sBAAsB,EAAE,GAAG,EAAE;QAC9B,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QAC3F,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QAC3F,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0BAA0B,EAAE,GAAG,EAAE;QAClC,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC;QAC7F,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACxE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;QAChG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+EAA+E,EAAE,GAAG,EAAE;QACvF,MAAM,EAAE,GAAG,mBAAmB,CAAC,EAAE,GAAG,SAAS,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAClE,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,KAAK,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACpH,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE,KAAK,EAAE,EAAE,aAAa,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACzH,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,4CAA4C,EAAE,GAAG,EAAE;IAC1D,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,kBAAkB,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,CAAC,CAAC;QAC1G,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,kBAAkB,CAAC,CAAC;QACjE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAC1D,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;QACzG,MAAM,CAAC,MAAM,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC/B,MAAM,CAAC,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,IAAI,CAAC;QACN,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QACjE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,WAAoB,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,EAAE,CAAC;QAC7F,CAAC,kBAAkB,EAAE,EAAE,IAAI,EAAE,kBAA2B,EAAE,aAAa,EAAE,EAAE,EAAE,CAAC;QAC9E,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;QACpF,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,SAAkB,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC;KACnD,CAAC,CAAC,0BAA0B,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;QAC9C,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAoB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACzD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACvC,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,+BAA+B,EAAE,GAAG,EAAE;IAC7C,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAkB;YAC5B,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE;YACpF,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YACpF,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,EAAE,WAAW,EAAE,UAAU,EAAE,EAAE;SAC9D,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;gBACpC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;YAC9B,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC9C,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gEAAgE,EAAE,GAAG,EAAE;QACxE,MAAM,EAAE,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC1C,MAAM,MAAM,GAAG,EAAE,CAAC,SAAS,CAAC;YAC1B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE;SACzC,CAAC,CAAC;QACH,gCAAgC;QAChC,MAAM,GAAG,GAAG,mBAAmB,CAAC,SAAS,CAAC,CAAC;QAC3C,GAAG,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,qBAAqB,EAAE,KAAK,EAAE,CAAC,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QACpG,MAAM,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC;YAC5B,IAAI,EAAE,qBAAqB;YAC3B,KAAK,EAAE,CAAC;YACR,KAAK,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,EAAE;SACzC,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC7C,KAAK,MAAM,CAAC,CAAC,+DAA+D;IAC9E,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * R4 integration test: verifies that tool_result messages are serialized into
3
+ * Claude-native tool_result blocks (NOT XML wrapping) when
4
+ * CC_OPENCLAW_TOOL_STREAM=1 is set.
5
+ *
6
+ * Tests the serializeToolResults function exported from openai-compat.ts and
7
+ * the extractUserMessage behaviour when the last message is role:tool.
8
+ * Also asserts that CC_OPENCLAW_TOOL_STREAM=0 preserves the legacy XML path.
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=tool-result-roundtrip.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-roundtrip.test.d.ts","sourceRoot":"","sources":["../../../tests/streaming/tool-result-roundtrip.test.ts"],"names":[],"mappings":"AACA;;;;;;;;GAQG"}