@jackchen_me/open-multi-agent 1.0.0 → 1.0.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 (80) hide show
  1. package/package.json +8 -2
  2. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -40
  3. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -23
  4. package/.github/pull_request_template.md +0 -14
  5. package/.github/workflows/ci.yml +0 -23
  6. package/CLAUDE.md +0 -80
  7. package/CODE_OF_CONDUCT.md +0 -48
  8. package/CONTRIBUTING.md +0 -72
  9. package/DECISIONS.md +0 -43
  10. package/README_zh.md +0 -277
  11. package/SECURITY.md +0 -17
  12. package/examples/01-single-agent.ts +0 -131
  13. package/examples/02-team-collaboration.ts +0 -167
  14. package/examples/03-task-pipeline.ts +0 -201
  15. package/examples/04-multi-model-team.ts +0 -261
  16. package/examples/05-copilot-test.ts +0 -49
  17. package/examples/06-local-model.ts +0 -200
  18. package/examples/07-fan-out-aggregate.ts +0 -209
  19. package/examples/08-gemma4-local.ts +0 -192
  20. package/examples/09-structured-output.ts +0 -73
  21. package/examples/10-task-retry.ts +0 -132
  22. package/examples/11-trace-observability.ts +0 -133
  23. package/examples/12-grok.ts +0 -154
  24. package/examples/13-gemini.ts +0 -48
  25. package/src/agent/agent.ts +0 -622
  26. package/src/agent/loop-detector.ts +0 -137
  27. package/src/agent/pool.ts +0 -285
  28. package/src/agent/runner.ts +0 -542
  29. package/src/agent/structured-output.ts +0 -126
  30. package/src/index.ts +0 -182
  31. package/src/llm/adapter.ts +0 -98
  32. package/src/llm/anthropic.ts +0 -389
  33. package/src/llm/copilot.ts +0 -552
  34. package/src/llm/gemini.ts +0 -378
  35. package/src/llm/grok.ts +0 -29
  36. package/src/llm/openai-common.ts +0 -294
  37. package/src/llm/openai.ts +0 -292
  38. package/src/memory/shared.ts +0 -181
  39. package/src/memory/store.ts +0 -124
  40. package/src/orchestrator/orchestrator.ts +0 -1071
  41. package/src/orchestrator/scheduler.ts +0 -352
  42. package/src/task/queue.ts +0 -464
  43. package/src/task/task.ts +0 -239
  44. package/src/team/messaging.ts +0 -232
  45. package/src/team/team.ts +0 -334
  46. package/src/tool/built-in/bash.ts +0 -187
  47. package/src/tool/built-in/file-edit.ts +0 -154
  48. package/src/tool/built-in/file-read.ts +0 -105
  49. package/src/tool/built-in/file-write.ts +0 -81
  50. package/src/tool/built-in/grep.ts +0 -362
  51. package/src/tool/built-in/index.ts +0 -50
  52. package/src/tool/executor.ts +0 -178
  53. package/src/tool/framework.ts +0 -557
  54. package/src/tool/text-tool-extractor.ts +0 -219
  55. package/src/types.ts +0 -542
  56. package/src/utils/semaphore.ts +0 -89
  57. package/src/utils/trace.ts +0 -34
  58. package/tests/agent-hooks.test.ts +0 -473
  59. package/tests/agent-pool.test.ts +0 -212
  60. package/tests/approval.test.ts +0 -464
  61. package/tests/built-in-tools.test.ts +0 -393
  62. package/tests/gemini-adapter.test.ts +0 -97
  63. package/tests/grok-adapter.test.ts +0 -74
  64. package/tests/llm-adapters.test.ts +0 -357
  65. package/tests/loop-detection.test.ts +0 -456
  66. package/tests/openai-fallback.test.ts +0 -159
  67. package/tests/orchestrator.test.ts +0 -281
  68. package/tests/scheduler.test.ts +0 -221
  69. package/tests/semaphore.test.ts +0 -57
  70. package/tests/shared-memory.test.ts +0 -122
  71. package/tests/structured-output.test.ts +0 -331
  72. package/tests/task-queue.test.ts +0 -244
  73. package/tests/task-retry.test.ts +0 -368
  74. package/tests/task-utils.test.ts +0 -155
  75. package/tests/team-messaging.test.ts +0 -329
  76. package/tests/text-tool-extractor.test.ts +0 -170
  77. package/tests/tool-executor.test.ts +0 -193
  78. package/tests/trace.test.ts +0 -453
  79. package/tsconfig.json +0 -25
  80. package/vitest.config.ts +0 -9
@@ -1,219 +0,0 @@
1
- /**
2
- * @fileoverview Fallback tool-call extractor for local models.
3
- *
4
- * When a local model (Ollama, vLLM, LM Studio) returns tool calls as plain
5
- * text instead of using the OpenAI `tool_calls` wire format, this module
6
- * attempts to extract them from the text output.
7
- *
8
- * Common scenarios:
9
- * - Ollama thinking-model bug: tool call JSON ends up inside unclosed `<think>` tags
10
- * - Model outputs raw JSON tool calls without the server parsing them
11
- * - Model wraps tool calls in markdown code fences
12
- * - Hermes-format `<tool_call>` tags
13
- *
14
- * This is a **safety net**, not the primary path. Native `tool_calls` from
15
- * the server are always preferred.
16
- */
17
-
18
- import type { ToolUseBlock } from '../types.js'
19
-
20
- // ---------------------------------------------------------------------------
21
- // ID generation
22
- // ---------------------------------------------------------------------------
23
-
24
- let callCounter = 0
25
-
26
- /** Generate a unique tool-call ID for extracted calls. */
27
- function generateToolCallId(): string {
28
- return `extracted_call_${Date.now()}_${++callCounter}`
29
- }
30
-
31
- // ---------------------------------------------------------------------------
32
- // Internal parsers
33
- // ---------------------------------------------------------------------------
34
-
35
- /**
36
- * Try to parse a single JSON object as a tool call.
37
- *
38
- * Accepted shapes:
39
- * ```json
40
- * { "name": "bash", "arguments": { "command": "ls" } }
41
- * { "name": "bash", "parameters": { "command": "ls" } }
42
- * { "function": { "name": "bash", "arguments": { "command": "ls" } } }
43
- * ```
44
- */
45
- function parseToolCallJSON(
46
- json: unknown,
47
- knownToolNames: ReadonlySet<string>,
48
- ): ToolUseBlock | null {
49
- if (json === null || typeof json !== 'object' || Array.isArray(json)) {
50
- return null
51
- }
52
-
53
- const obj = json as Record<string, unknown>
54
-
55
- // Shape: { function: { name, arguments } }
56
- if (typeof obj['function'] === 'object' && obj['function'] !== null) {
57
- const fn = obj['function'] as Record<string, unknown>
58
- return parseFlat(fn, knownToolNames)
59
- }
60
-
61
- // Shape: { name, arguments|parameters }
62
- return parseFlat(obj, knownToolNames)
63
- }
64
-
65
- function parseFlat(
66
- obj: Record<string, unknown>,
67
- knownToolNames: ReadonlySet<string>,
68
- ): ToolUseBlock | null {
69
- const name = obj['name']
70
- if (typeof name !== 'string' || name.length === 0) return null
71
-
72
- // Whitelist check — don't treat arbitrary JSON as a tool call
73
- if (knownToolNames.size > 0 && !knownToolNames.has(name)) return null
74
-
75
- let input: Record<string, unknown> = {}
76
- const args = obj['arguments'] ?? obj['parameters'] ?? obj['input']
77
- if (args !== null && args !== undefined) {
78
- if (typeof args === 'string') {
79
- try {
80
- const parsed = JSON.parse(args)
81
- if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
82
- input = parsed as Record<string, unknown>
83
- }
84
- } catch {
85
- // Malformed — use empty input
86
- }
87
- } else if (typeof args === 'object' && !Array.isArray(args)) {
88
- input = args as Record<string, unknown>
89
- }
90
- }
91
-
92
- return {
93
- type: 'tool_use',
94
- id: generateToolCallId(),
95
- name,
96
- input,
97
- }
98
- }
99
-
100
- // ---------------------------------------------------------------------------
101
- // JSON extraction from text
102
- // ---------------------------------------------------------------------------
103
-
104
- /**
105
- * Find all top-level JSON objects in a string by tracking brace depth.
106
- * Returns the parsed objects (not sub-objects).
107
- */
108
- function extractJSONObjects(text: string): unknown[] {
109
- const results: unknown[] = []
110
- let depth = 0
111
- let start = -1
112
- let inString = false
113
- let escape = false
114
-
115
- for (let i = 0; i < text.length; i++) {
116
- const ch = text[i]!
117
-
118
- if (escape) {
119
- escape = false
120
- continue
121
- }
122
-
123
- if (ch === '\\' && inString) {
124
- escape = true
125
- continue
126
- }
127
-
128
- if (ch === '"') {
129
- inString = !inString
130
- continue
131
- }
132
-
133
- if (inString) continue
134
-
135
- if (ch === '{') {
136
- if (depth === 0) start = i
137
- depth++
138
- } else if (ch === '}') {
139
- depth--
140
- if (depth === 0 && start !== -1) {
141
- const candidate = text.slice(start, i + 1)
142
- try {
143
- results.push(JSON.parse(candidate))
144
- } catch {
145
- // Not valid JSON — skip
146
- }
147
- start = -1
148
- }
149
- }
150
- }
151
-
152
- return results
153
- }
154
-
155
- // ---------------------------------------------------------------------------
156
- // Hermes format: <tool_call>...</tool_call>
157
- // ---------------------------------------------------------------------------
158
-
159
- function extractHermesToolCalls(
160
- text: string,
161
- knownToolNames: ReadonlySet<string>,
162
- ): ToolUseBlock[] {
163
- const results: ToolUseBlock[] = []
164
-
165
- for (const match of text.matchAll(/<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g)) {
166
- const inner = match[1]!.trim()
167
- try {
168
- const parsed: unknown = JSON.parse(inner)
169
- const block = parseToolCallJSON(parsed, knownToolNames)
170
- if (block !== null) results.push(block)
171
- } catch {
172
- // Malformed hermes content — skip
173
- }
174
- }
175
-
176
- return results
177
- }
178
-
179
- // ---------------------------------------------------------------------------
180
- // Public API
181
- // ---------------------------------------------------------------------------
182
-
183
- /**
184
- * Attempt to extract tool calls from a model's text output.
185
- *
186
- * Tries multiple strategies in order:
187
- * 1. Hermes `<tool_call>` tags
188
- * 2. JSON objects in text (bare or inside code fences)
189
- *
190
- * @param text - The model's text output.
191
- * @param knownToolNames - Whitelist of registered tool names. When non-empty,
192
- * only JSON objects whose `name` matches a known tool
193
- * are treated as tool calls.
194
- * @returns Extracted {@link ToolUseBlock}s, or an empty array if none found.
195
- */
196
- export function extractToolCallsFromText(
197
- text: string,
198
- knownToolNames: string[],
199
- ): ToolUseBlock[] {
200
- if (text.length === 0) return []
201
-
202
- const nameSet = new Set(knownToolNames)
203
-
204
- // Strategy 1: Hermes format
205
- const hermesResults = extractHermesToolCalls(text, nameSet)
206
- if (hermesResults.length > 0) return hermesResults
207
-
208
- // Strategy 2: Strip code fences, then extract JSON objects
209
- const stripped = text.replace(/```(?:json)?\s*\n?([\s\S]*?)\n?\s*```/g, '$1')
210
- const jsonObjects = extractJSONObjects(stripped)
211
-
212
- const results: ToolUseBlock[] = []
213
- for (const obj of jsonObjects) {
214
- const block = parseToolCallJSON(obj, nameSet)
215
- if (block !== null) results.push(block)
216
- }
217
-
218
- return results
219
- }