@morphllm/subagents 0.1.3 → 0.1.4
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/dist/base-client-B7fgl_Wg.d.mts +30 -0
- package/dist/base-client-C6pbtqLX.d.ts +30 -0
- package/dist/core/index.d.mts +4 -30
- package/dist/core/index.d.ts +4 -30
- package/dist/docx/index.d.mts +193 -11
- package/dist/docx/index.d.ts +193 -11
- package/dist/docx/index.js +156 -402
- package/dist/docx/index.js.map +1 -1
- package/dist/docx/index.mjs +156 -402
- package/dist/docx/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +164 -263
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +164 -263
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/docx/agent.ts +134 -274
- package/src/docx/client.ts +58 -1
- package/src/docx/types.ts +146 -2
package/dist/docx/index.mjs
CHANGED
|
@@ -67,7 +67,7 @@ var BaseClient = class {
|
|
|
67
67
|
};
|
|
68
68
|
|
|
69
69
|
// src/docx/client.ts
|
|
70
|
-
var DEFAULT_API_URL = "https://
|
|
70
|
+
var DEFAULT_API_URL = "https://subagents.morphllm.com/v1/morph-docx";
|
|
71
71
|
var DocxClient = class extends BaseClient {
|
|
72
72
|
constructor(options = {}) {
|
|
73
73
|
super(options);
|
|
@@ -113,333 +113,60 @@ var DocxClient = class extends BaseClient {
|
|
|
113
113
|
async deleteDocument(docId) {
|
|
114
114
|
return this.delete(`/documents/${docId}`);
|
|
115
115
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
this.
|
|
122
|
-
this.model = options.model || this.getDefaultModel();
|
|
123
|
-
this.instructions = options.instructions || this.getDefaultInstructions();
|
|
124
|
-
this.client = options.client;
|
|
116
|
+
// --- Creation Operations ---
|
|
117
|
+
/**
|
|
118
|
+
* Create a new empty DOCX document.
|
|
119
|
+
*/
|
|
120
|
+
async create(title) {
|
|
121
|
+
return this.post("/documents/create", { title });
|
|
125
122
|
}
|
|
126
|
-
/**
|
|
127
|
-
|
|
128
|
-
|
|
123
|
+
/**
|
|
124
|
+
* Execute build operations on a document (add content).
|
|
125
|
+
*/
|
|
126
|
+
async build(docId, operations) {
|
|
127
|
+
return this.post(`/documents/${docId}/build`, { operations });
|
|
129
128
|
}
|
|
130
129
|
/**
|
|
131
|
-
*
|
|
132
|
-
* Returns the final response and all tool calls made.
|
|
130
|
+
* Get document information.
|
|
133
131
|
*/
|
|
134
|
-
async
|
|
135
|
-
|
|
136
|
-
throw new Error("OpenAI client is required for agent.run(). Pass it in the constructor options.");
|
|
137
|
-
}
|
|
138
|
-
const messages = [
|
|
139
|
-
{ role: "system", content: this.instructions },
|
|
140
|
-
...conversationHistory,
|
|
141
|
-
{ role: "user", content: userMessage }
|
|
142
|
-
];
|
|
143
|
-
const toolCalls = [];
|
|
144
|
-
let response = "";
|
|
145
|
-
const tools = this.getTools();
|
|
146
|
-
while (true) {
|
|
147
|
-
const completion = await this.openai.chat.completions.create({
|
|
148
|
-
model: this.model,
|
|
149
|
-
messages,
|
|
150
|
-
tools,
|
|
151
|
-
tool_choice: "auto"
|
|
152
|
-
});
|
|
153
|
-
const assistantMessage = completion.choices[0].message;
|
|
154
|
-
if (assistantMessage.tool_calls && assistantMessage.tool_calls.length > 0) {
|
|
155
|
-
messages.push({
|
|
156
|
-
role: "assistant",
|
|
157
|
-
content: assistantMessage.content || ""
|
|
158
|
-
});
|
|
159
|
-
for (const tc of assistantMessage.tool_calls) {
|
|
160
|
-
const fn = tc.function;
|
|
161
|
-
const args = JSON.parse(fn.arguments);
|
|
162
|
-
const toolCall = {
|
|
163
|
-
id: tc.id,
|
|
164
|
-
name: fn.name,
|
|
165
|
-
arguments: args,
|
|
166
|
-
status: "running"
|
|
167
|
-
};
|
|
168
|
-
toolCalls.push(toolCall);
|
|
169
|
-
const result = await this.executeTool(fn.name, args);
|
|
170
|
-
if (result.startsWith("Error:")) {
|
|
171
|
-
toolCall.error = result;
|
|
172
|
-
toolCall.status = "error";
|
|
173
|
-
} else {
|
|
174
|
-
toolCall.result = result;
|
|
175
|
-
toolCall.status = "completed";
|
|
176
|
-
}
|
|
177
|
-
messages.push({
|
|
178
|
-
role: "tool",
|
|
179
|
-
content: result,
|
|
180
|
-
tool_call_id: tc.id
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
} else {
|
|
184
|
-
response = assistantMessage.content || "";
|
|
185
|
-
break;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return { response, toolCalls };
|
|
132
|
+
async getInfo(docId) {
|
|
133
|
+
return this.get(`/documents/${docId}/info`);
|
|
189
134
|
}
|
|
135
|
+
// --- Convenience Methods ---
|
|
190
136
|
/**
|
|
191
|
-
*
|
|
192
|
-
* Yields events for real-time UI updates.
|
|
137
|
+
* Add a heading to the document.
|
|
193
138
|
*/
|
|
194
|
-
async
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const toolCallBuffers = /* @__PURE__ */ new Map();
|
|
215
|
-
for await (const chunk of stream) {
|
|
216
|
-
const delta = chunk.choices[0]?.delta;
|
|
217
|
-
if (delta?.content) {
|
|
218
|
-
contentBuffer += delta.content;
|
|
219
|
-
yield { type: "content_delta", delta: { text: delta.content } };
|
|
220
|
-
}
|
|
221
|
-
if (delta?.tool_calls) {
|
|
222
|
-
for (const tc of delta.tool_calls) {
|
|
223
|
-
const idx = tc.index;
|
|
224
|
-
if (!toolCallBuffers.has(idx)) {
|
|
225
|
-
toolCallBuffers.set(idx, { id: "", name: "", arguments: "" });
|
|
226
|
-
}
|
|
227
|
-
const buffer = toolCallBuffers.get(idx);
|
|
228
|
-
if (tc.id) buffer.id = tc.id;
|
|
229
|
-
if (tc.function?.name) buffer.name = tc.function.name;
|
|
230
|
-
if (tc.function?.arguments) buffer.arguments += tc.function.arguments;
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
if (toolCallBuffers.size > 0) {
|
|
235
|
-
messages.push({
|
|
236
|
-
role: "assistant",
|
|
237
|
-
content: contentBuffer
|
|
238
|
-
});
|
|
239
|
-
for (const [_, buffer] of toolCallBuffers) {
|
|
240
|
-
const args = JSON.parse(buffer.arguments);
|
|
241
|
-
yield {
|
|
242
|
-
type: "tool_start",
|
|
243
|
-
tool: { id: buffer.id, name: buffer.name, arguments: args }
|
|
244
|
-
};
|
|
245
|
-
const result = await this.executeTool(buffer.name, args);
|
|
246
|
-
if (result.startsWith("Error:")) {
|
|
247
|
-
yield { type: "tool_end", tool: { id: buffer.id, error: result } };
|
|
248
|
-
} else {
|
|
249
|
-
yield { type: "tool_end", tool: { id: buffer.id, result } };
|
|
250
|
-
}
|
|
251
|
-
messages.push({
|
|
252
|
-
role: "tool",
|
|
253
|
-
content: result,
|
|
254
|
-
tool_call_id: buffer.id
|
|
255
|
-
});
|
|
256
|
-
}
|
|
257
|
-
} else {
|
|
258
|
-
yield { type: "message_end" };
|
|
259
|
-
break;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
139
|
+
async addHeading(docId, text, level = 1) {
|
|
140
|
+
return this.build(docId, [{ type: "add_heading", text, level }]);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Add a paragraph to the document.
|
|
144
|
+
*/
|
|
145
|
+
async addParagraph(docId, text, options) {
|
|
146
|
+
return this.build(docId, [{ type: "add_paragraph", text, ...options }]);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Add a table to the document.
|
|
150
|
+
*/
|
|
151
|
+
async addTable(docId, headers, rows) {
|
|
152
|
+
return this.build(docId, [{ type: "add_table", headers, rows }]);
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Add page numbers to the document.
|
|
156
|
+
*/
|
|
157
|
+
async addPageNumbers(docId, format = "Page {PAGE} of {NUMPAGES}") {
|
|
158
|
+
return this.build(docId, [{ type: "add_page_numbers", format_string: format }]);
|
|
262
159
|
}
|
|
263
160
|
};
|
|
264
161
|
|
|
265
162
|
// src/docx/agent.ts
|
|
266
|
-
var
|
|
267
|
-
|
|
268
|
-
When editing documents:
|
|
269
|
-
1. First read the document to understand its structure
|
|
270
|
-
2. Use track changes for all modifications
|
|
271
|
-
3. Add comments to flag issues or request clarification
|
|
272
|
-
4. Be precise with paragraph text matching - use unique text snippets
|
|
273
|
-
|
|
274
|
-
Available tools:
|
|
275
|
-
- read_document: Read the document content
|
|
276
|
-
- add_comment: Add a comment to a specific paragraph
|
|
277
|
-
- insert_text: Insert text within a paragraph (tracked change)
|
|
278
|
-
- propose_deletion: Mark text for deletion (tracked change)
|
|
279
|
-
- reply_comment: Reply to an existing comment
|
|
280
|
-
- resolve_comment: Mark a comment as resolved
|
|
281
|
-
- delete_comment: Delete a comment
|
|
282
|
-
- insert_paragraph: Insert a new paragraph
|
|
283
|
-
- validate_document: Validate DOCX structure`;
|
|
284
|
-
var TOOLS = [
|
|
285
|
-
{
|
|
286
|
-
type: "function",
|
|
287
|
-
function: {
|
|
288
|
-
name: "read_document",
|
|
289
|
-
description: "Read the document content as plain text",
|
|
290
|
-
parameters: {
|
|
291
|
-
type: "object",
|
|
292
|
-
properties: {
|
|
293
|
-
doc_id: { type: "string", description: "Document ID" }
|
|
294
|
-
},
|
|
295
|
-
required: ["doc_id"]
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
},
|
|
299
|
-
{
|
|
300
|
-
type: "function",
|
|
301
|
-
function: {
|
|
302
|
-
name: "add_comment",
|
|
303
|
-
description: "Add a comment to a specific paragraph in the document",
|
|
304
|
-
parameters: {
|
|
305
|
-
type: "object",
|
|
306
|
-
properties: {
|
|
307
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
308
|
-
para_text: { type: "string", description: "Unique text from the target paragraph" },
|
|
309
|
-
comment: { type: "string", description: "Comment text to add" },
|
|
310
|
-
highlight: { type: "string", description: "Optional specific text to highlight" }
|
|
311
|
-
},
|
|
312
|
-
required: ["doc_id", "para_text", "comment"]
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
},
|
|
316
|
-
{
|
|
317
|
-
type: "function",
|
|
318
|
-
function: {
|
|
319
|
-
name: "insert_text",
|
|
320
|
-
description: "Insert text within a paragraph (creates a tracked change)",
|
|
321
|
-
parameters: {
|
|
322
|
-
type: "object",
|
|
323
|
-
properties: {
|
|
324
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
325
|
-
para_text: { type: "string", description: "Unique text from the target paragraph" },
|
|
326
|
-
after: { type: "string", description: "Text after which to insert" },
|
|
327
|
-
new_text: { type: "string", description: "Text to insert" }
|
|
328
|
-
},
|
|
329
|
-
required: ["doc_id", "para_text", "after", "new_text"]
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
},
|
|
333
|
-
{
|
|
334
|
-
type: "function",
|
|
335
|
-
function: {
|
|
336
|
-
name: "propose_deletion",
|
|
337
|
-
description: "Mark text for deletion (creates a tracked change)",
|
|
338
|
-
parameters: {
|
|
339
|
-
type: "object",
|
|
340
|
-
properties: {
|
|
341
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
342
|
-
para_text: { type: "string", description: "Unique text from the target paragraph" },
|
|
343
|
-
target: { type: "string", description: "Specific text to delete (optional, defaults to whole paragraph)" }
|
|
344
|
-
},
|
|
345
|
-
required: ["doc_id", "para_text"]
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
},
|
|
349
|
-
{
|
|
350
|
-
type: "function",
|
|
351
|
-
function: {
|
|
352
|
-
name: "reply_comment",
|
|
353
|
-
description: "Reply to an existing comment",
|
|
354
|
-
parameters: {
|
|
355
|
-
type: "object",
|
|
356
|
-
properties: {
|
|
357
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
358
|
-
comment_id: { type: "string", description: "ID of the comment to reply to" },
|
|
359
|
-
reply: { type: "string", description: "Reply text" }
|
|
360
|
-
},
|
|
361
|
-
required: ["doc_id", "comment_id", "reply"]
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
},
|
|
365
|
-
{
|
|
366
|
-
type: "function",
|
|
367
|
-
function: {
|
|
368
|
-
name: "resolve_comment",
|
|
369
|
-
description: "Mark a comment as resolved",
|
|
370
|
-
parameters: {
|
|
371
|
-
type: "object",
|
|
372
|
-
properties: {
|
|
373
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
374
|
-
comment_id: { type: "string", description: "ID of the comment to resolve" }
|
|
375
|
-
},
|
|
376
|
-
required: ["doc_id", "comment_id"]
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
},
|
|
380
|
-
{
|
|
381
|
-
type: "function",
|
|
382
|
-
function: {
|
|
383
|
-
name: "delete_comment",
|
|
384
|
-
description: "Delete a comment and its replies",
|
|
385
|
-
parameters: {
|
|
386
|
-
type: "object",
|
|
387
|
-
properties: {
|
|
388
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
389
|
-
comment_id: { type: "string", description: "ID of the comment to delete" }
|
|
390
|
-
},
|
|
391
|
-
required: ["doc_id", "comment_id"]
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
},
|
|
395
|
-
{
|
|
396
|
-
type: "function",
|
|
397
|
-
function: {
|
|
398
|
-
name: "insert_paragraph",
|
|
399
|
-
description: "Insert a new paragraph after existing text",
|
|
400
|
-
parameters: {
|
|
401
|
-
type: "object",
|
|
402
|
-
properties: {
|
|
403
|
-
doc_id: { type: "string", description: "Document ID" },
|
|
404
|
-
after_text: { type: "string", description: "Text after which to insert the new paragraph" },
|
|
405
|
-
new_text: { type: "string", description: "Content of the new paragraph" }
|
|
406
|
-
},
|
|
407
|
-
required: ["doc_id", "after_text", "new_text"]
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
},
|
|
411
|
-
{
|
|
412
|
-
type: "function",
|
|
413
|
-
function: {
|
|
414
|
-
name: "validate_document",
|
|
415
|
-
description: "Validate the document structure",
|
|
416
|
-
parameters: {
|
|
417
|
-
type: "object",
|
|
418
|
-
properties: {
|
|
419
|
-
doc_id: { type: "string", description: "Document ID" }
|
|
420
|
-
},
|
|
421
|
-
required: ["doc_id"]
|
|
422
|
-
}
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
];
|
|
426
|
-
var DocxAgent = class extends BaseAgent {
|
|
163
|
+
var DEFAULT_BASE_URL = "https://subagents.morphllm.com/v1";
|
|
164
|
+
var DocxAgent = class {
|
|
427
165
|
constructor(options = {}) {
|
|
428
|
-
|
|
429
|
-
|
|
166
|
+
this.baseUrl = options.baseUrl || process.env.MORPH_API_URL || DEFAULT_BASE_URL;
|
|
167
|
+
this.apiKey = options.apiKey || process.env.MORPH_API_KEY || "";
|
|
430
168
|
this.documentId = options.documentId;
|
|
431
169
|
}
|
|
432
|
-
getDefaultModel() {
|
|
433
|
-
return "moonshot-v1-32k";
|
|
434
|
-
}
|
|
435
|
-
getDefaultInstructions() {
|
|
436
|
-
return this.documentId ? `${DEFAULT_INSTRUCTIONS}
|
|
437
|
-
|
|
438
|
-
Current document ID: ${this.documentId}` : DEFAULT_INSTRUCTIONS;
|
|
439
|
-
}
|
|
440
|
-
getTools() {
|
|
441
|
-
return TOOLS;
|
|
442
|
-
}
|
|
443
170
|
/** Set the current document ID */
|
|
444
171
|
setDocument(docId) {
|
|
445
172
|
this.documentId = docId;
|
|
@@ -448,100 +175,127 @@ Current document ID: ${this.documentId}` : DEFAULT_INSTRUCTIONS;
|
|
|
448
175
|
getDocumentId() {
|
|
449
176
|
return this.documentId;
|
|
450
177
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Send a chat completion request (non-streaming).
|
|
180
|
+
* This runs the full agent loop on the server and returns the final response.
|
|
181
|
+
*/
|
|
182
|
+
async chat(messages) {
|
|
183
|
+
const contextMessages = this.documentId ? messages.map((m, i) => {
|
|
184
|
+
if (i === messages.length - 1 && m.role === "user") {
|
|
185
|
+
return {
|
|
186
|
+
...m,
|
|
187
|
+
content: `[Document ID: ${this.documentId}]
|
|
188
|
+
|
|
189
|
+
${m.content}`
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return m;
|
|
193
|
+
}) : messages;
|
|
194
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
195
|
+
method: "POST",
|
|
196
|
+
headers: {
|
|
197
|
+
"Content-Type": "application/json",
|
|
198
|
+
...this.apiKey && { Authorization: `Bearer ${this.apiKey}` }
|
|
199
|
+
},
|
|
200
|
+
body: JSON.stringify({
|
|
201
|
+
model: "morph-docx",
|
|
202
|
+
messages: contextMessages,
|
|
203
|
+
stream: false
|
|
204
|
+
})
|
|
205
|
+
});
|
|
206
|
+
if (!response.ok) {
|
|
207
|
+
const error = await response.text();
|
|
208
|
+
throw new Error(`API error: ${error}`);
|
|
455
209
|
}
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
210
|
+
return response.json();
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Send a streaming chat completion request.
|
|
214
|
+
* Returns an async generator that yields chunks as they arrive.
|
|
215
|
+
*/
|
|
216
|
+
async *chatStream(messages) {
|
|
217
|
+
const contextMessages = this.documentId ? messages.map((m, i) => {
|
|
218
|
+
if (i === messages.length - 1 && m.role === "user") {
|
|
219
|
+
return {
|
|
220
|
+
...m,
|
|
221
|
+
content: `[Document ID: ${this.documentId}]
|
|
461
222
|
|
|
462
|
-
${
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
]);
|
|
504
|
-
return result.results[0];
|
|
505
|
-
}
|
|
506
|
-
case "resolve_comment": {
|
|
507
|
-
const result = await this.client.edit(docId, [
|
|
508
|
-
{
|
|
509
|
-
type: "resolve_comment",
|
|
510
|
-
comment_id: args.comment_id
|
|
511
|
-
}
|
|
512
|
-
]);
|
|
513
|
-
return result.results[0];
|
|
514
|
-
}
|
|
515
|
-
case "delete_comment": {
|
|
516
|
-
const result = await this.client.edit(docId, [
|
|
517
|
-
{
|
|
518
|
-
type: "delete_comment",
|
|
519
|
-
comment_id: args.comment_id
|
|
520
|
-
}
|
|
521
|
-
]);
|
|
522
|
-
return result.results[0];
|
|
523
|
-
}
|
|
524
|
-
case "insert_paragraph": {
|
|
525
|
-
const result = await this.client.edit(docId, [
|
|
526
|
-
{
|
|
527
|
-
type: "insert_paragraph",
|
|
528
|
-
after_text: args.after_text,
|
|
529
|
-
new_text: args.new_text
|
|
530
|
-
}
|
|
531
|
-
]);
|
|
532
|
-
return result.results[0];
|
|
533
|
-
}
|
|
534
|
-
case "validate_document": {
|
|
535
|
-
const result = await this.client.validate(docId);
|
|
536
|
-
return `${result.result}: ${result.output}`;
|
|
223
|
+
${m.content}`
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
return m;
|
|
227
|
+
}) : messages;
|
|
228
|
+
const response = await fetch(`${this.baseUrl}/chat/completions`, {
|
|
229
|
+
method: "POST",
|
|
230
|
+
headers: {
|
|
231
|
+
"Content-Type": "application/json",
|
|
232
|
+
...this.apiKey && { Authorization: `Bearer ${this.apiKey}` }
|
|
233
|
+
},
|
|
234
|
+
body: JSON.stringify({
|
|
235
|
+
model: "morph-docx",
|
|
236
|
+
messages: contextMessages,
|
|
237
|
+
stream: true
|
|
238
|
+
})
|
|
239
|
+
});
|
|
240
|
+
if (!response.ok) {
|
|
241
|
+
const error = await response.text();
|
|
242
|
+
throw new Error(`API error: ${error}`);
|
|
243
|
+
}
|
|
244
|
+
const reader = response.body?.getReader();
|
|
245
|
+
if (!reader) {
|
|
246
|
+
throw new Error("No response body");
|
|
247
|
+
}
|
|
248
|
+
const decoder = new TextDecoder();
|
|
249
|
+
let buffer = "";
|
|
250
|
+
while (true) {
|
|
251
|
+
const { done, value } = await reader.read();
|
|
252
|
+
if (done) break;
|
|
253
|
+
buffer += decoder.decode(value, { stream: true });
|
|
254
|
+
const lines = buffer.split("\n");
|
|
255
|
+
buffer = lines.pop() || "";
|
|
256
|
+
for (const line of lines) {
|
|
257
|
+
if (!line.startsWith("data: ")) continue;
|
|
258
|
+
const data = line.slice(6).trim();
|
|
259
|
+
if (data === "[DONE]") return;
|
|
260
|
+
try {
|
|
261
|
+
const chunk = JSON.parse(data);
|
|
262
|
+
yield chunk;
|
|
263
|
+
} catch {
|
|
537
264
|
}
|
|
538
|
-
default:
|
|
539
|
-
return `Error: Unknown tool '${name}'`;
|
|
540
265
|
}
|
|
541
|
-
} catch (error) {
|
|
542
|
-
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|
|
543
266
|
}
|
|
544
267
|
}
|
|
268
|
+
/**
|
|
269
|
+
* Helper: Simple completion that returns just the content string.
|
|
270
|
+
*/
|
|
271
|
+
async complete(userMessage) {
|
|
272
|
+
const response = await this.chat([{ role: "user", content: userMessage }]);
|
|
273
|
+
return response.choices[0]?.message?.content || "";
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Create an OpenAI-compatible client configuration.
|
|
277
|
+
* Use this with the OpenAI SDK or OpenAI Agents SDK.
|
|
278
|
+
*
|
|
279
|
+
* @example
|
|
280
|
+
* ```typescript
|
|
281
|
+
* import OpenAI from 'openai';
|
|
282
|
+
* import { DocxAgent } from '@morphllm/subagents/docx';
|
|
283
|
+
*
|
|
284
|
+
* const agent = new DocxAgent();
|
|
285
|
+
* const openai = new OpenAI(agent.getOpenAIConfig());
|
|
286
|
+
*
|
|
287
|
+
* const response = await openai.chat.completions.create({
|
|
288
|
+
* model: 'morph-docx',
|
|
289
|
+
* messages: [{ role: 'user', content: 'Hello!' }],
|
|
290
|
+
* });
|
|
291
|
+
* ```
|
|
292
|
+
*/
|
|
293
|
+
getOpenAIConfig() {
|
|
294
|
+
return {
|
|
295
|
+
baseURL: this.baseUrl,
|
|
296
|
+
apiKey: this.apiKey || "not-required"
|
|
297
|
+
};
|
|
298
|
+
}
|
|
545
299
|
};
|
|
546
300
|
|
|
547
301
|
export { DocxAgent, DocxClient };
|