@unboundai/tb-ppt-mgagent 0.2.0 → 0.3.0
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/README.md +11 -2
- package/build/index.js +60 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -49,13 +49,22 @@ Every tool call writes one JSON-lines entry to `TB_PPT_LOG_FILE` (default `logs/
|
|
|
49
49
|
| `started` | either | call received, with its key arguments (outline preview/length, or sessionId) |
|
|
50
50
|
| `success` | `generate_tb_powerpoint` | session created; includes `sessionId` |
|
|
51
51
|
| `not_ready` | `get_tb_powerpoint_result` | session isn't `idle` yet; includes `sessionStatus` |
|
|
52
|
+
| `agent_message` | `get_tb_powerpoint_result` | the agent's own most recent `agent.message` text, up to 500 chars, in `agentMessagePreview` — this is what the agent actually said, not our derived status. Logged once the session is idle, before the stop-reason check, so it's there even on `not_end_turn` |
|
|
52
53
|
| `not_end_turn` | `get_tb_powerpoint_result` | idle, but `stop_reason` wasn't `end_turn`; includes `stopReason` |
|
|
54
|
+
| `listing_files` | `get_tb_powerpoint_result` | about to call Files API `list` for this session |
|
|
55
|
+
| `files_listed` | `get_tb_powerpoint_result` | includes `fileCount`, every `.pptx` candidate found (`pptxCandidates`, each with `id`/`filename`/`sizeBytes`), and which one was `chosenFileId` |
|
|
53
56
|
| `no_output_file` | `get_tb_powerpoint_result` | finished cleanly but no `.pptx` found; includes `fileCount` |
|
|
54
|
-
| `
|
|
57
|
+
| `download_started` | `get_tb_powerpoint_result` | about to call Files API `download`; includes `fileId`, `filename`, `expectedSizeBytes` |
|
|
58
|
+
| `download_completed` | `get_tb_powerpoint_result` | bytes received; includes `downloadedBytes` |
|
|
59
|
+
| `saving_file` | `get_tb_powerpoint_result` | about to write to `destPath` inside `outputDir` |
|
|
60
|
+
| `file_saved` | `get_tb_powerpoint_result` | write confirmed via `fs.statSync`; includes `savedBytes` and `bytesMatch` (should be `true`) |
|
|
61
|
+
| `success` | `get_tb_powerpoint_result` | fully done; includes `filename`, `destPath`, `downloadUrl` |
|
|
55
62
|
| `invalid_arguments` | either | zod validation failed; includes `details` |
|
|
56
63
|
| `error` | either | anything else threw; includes `message` |
|
|
57
64
|
|
|
58
|
-
|
|
65
|
+
The agent's actual final message is also returned to the caller as `agentMessage` on every `get_tb_powerpoint_result` response (not just logged), so a not-quite-right run can be diagnosed from the tool's own output, not just the log file.
|
|
66
|
+
|
|
67
|
+
All entries include `durationMs` except the intermediate progress lines (`agent_message`, `listing_files`, `files_listed`, `download_started`, `download_completed`, `saving_file`) — those are pure checkpoints, timed by their surrounding `started`/`success`/`error` lines instead. To see what's been run:
|
|
59
68
|
|
|
60
69
|
```bash
|
|
61
70
|
tail -f logs/tasks.log
|
package/build/index.js
CHANGED
|
@@ -268,15 +268,35 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
268
268
|
}]
|
|
269
269
|
};
|
|
270
270
|
}
|
|
271
|
-
// Find the most recent session.status_idle event to read its stop_reason
|
|
271
|
+
// Find the most recent session.status_idle event to read its stop_reason, and
|
|
272
|
+
// the most recent agent.message event so we can log/return what the agent
|
|
273
|
+
// actually said (not just our own derived status).
|
|
272
274
|
let latestIdleEvent = null;
|
|
275
|
+
let latestAgentMessage = null;
|
|
273
276
|
for await (const event of client.beta.sessions.events.list(sessionId)) {
|
|
274
277
|
if (event.type === "session.status_idle") {
|
|
275
278
|
if (!latestIdleEvent || event.processed_at > latestIdleEvent.processed_at) {
|
|
276
279
|
latestIdleEvent = event;
|
|
277
280
|
}
|
|
278
281
|
}
|
|
282
|
+
else if (event.type === "agent.message") {
|
|
283
|
+
const text = event.content
|
|
284
|
+
.filter((block) => block.type === "text")
|
|
285
|
+
.map((block) => block.text)
|
|
286
|
+
.join("\n")
|
|
287
|
+
.trim();
|
|
288
|
+
if (text && (!latestAgentMessage || event.processed_at > latestAgentMessage.processed_at)) {
|
|
289
|
+
latestAgentMessage = { processed_at: event.processed_at, text };
|
|
290
|
+
}
|
|
291
|
+
}
|
|
279
292
|
}
|
|
293
|
+
const agentMessagePreview = latestAgentMessage ? latestAgentMessage.text.slice(0, 500) : null;
|
|
294
|
+
logTask({
|
|
295
|
+
tool: name,
|
|
296
|
+
status: "agent_message",
|
|
297
|
+
sessionId,
|
|
298
|
+
agentMessagePreview
|
|
299
|
+
});
|
|
280
300
|
const stopReasonType = latestIdleEvent?.stop_reason.type;
|
|
281
301
|
if (stopReasonType !== "end_turn") {
|
|
282
302
|
logTask({
|
|
@@ -293,12 +313,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
293
313
|
ready: false,
|
|
294
314
|
status: session.status,
|
|
295
315
|
stopReason: stopReasonType ?? null,
|
|
316
|
+
agentMessage: agentMessagePreview,
|
|
296
317
|
message: `Session is idle but its stop reason is "${stopReasonType ?? "unknown"}", not "end_turn" - not fetching files yet.`
|
|
297
318
|
}, null, 2)
|
|
298
319
|
}]
|
|
299
320
|
};
|
|
300
321
|
}
|
|
301
322
|
// Session finished cleanly - look for a .pptx output file.
|
|
323
|
+
logTask({ tool: name, status: "listing_files", sessionId });
|
|
302
324
|
const files = await client.beta.files.list({
|
|
303
325
|
scope_id: sessionId,
|
|
304
326
|
betas: [MANAGED_AGENTS_BETA]
|
|
@@ -307,6 +329,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
307
329
|
const pptxFiles = fileList.filter((f) => /\.pptx$/i.test(f.filename));
|
|
308
330
|
const outputPptxFiles = pptxFiles.filter((f) => /outputs?[\\/]/i.test(f.filename));
|
|
309
331
|
const chosen = outputPptxFiles[0] ?? pptxFiles[0];
|
|
332
|
+
logTask({
|
|
333
|
+
tool: name,
|
|
334
|
+
status: "files_listed",
|
|
335
|
+
sessionId,
|
|
336
|
+
fileCount: fileList.length,
|
|
337
|
+
pptxCandidates: pptxFiles.map((f) => ({ id: f.id, filename: f.filename, sizeBytes: f.size_bytes })),
|
|
338
|
+
chosenFileId: chosen?.id ?? null
|
|
339
|
+
});
|
|
310
340
|
if (!chosen) {
|
|
311
341
|
logTask({
|
|
312
342
|
tool: name,
|
|
@@ -322,6 +352,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
322
352
|
ready: true,
|
|
323
353
|
status: "idle",
|
|
324
354
|
stopReason: "end_turn",
|
|
355
|
+
agentMessage: agentMessagePreview,
|
|
325
356
|
message: "Session finished but no .pptx output file was found.",
|
|
326
357
|
sessionFiles: fileList.map((f) => ({ id: f.id, filename: f.filename }))
|
|
327
358
|
}, null, 2)
|
|
@@ -331,20 +362,47 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
331
362
|
const { outputDir, publicUrlBase } = requireOutputConfig();
|
|
332
363
|
const safeName = path.basename(chosen.filename || `${sessionId}.pptx`);
|
|
333
364
|
const destPath = path.join(outputDir, safeName);
|
|
365
|
+
logTask({
|
|
366
|
+
tool: name,
|
|
367
|
+
status: "download_started",
|
|
368
|
+
sessionId,
|
|
369
|
+
fileId: chosen.id,
|
|
370
|
+
filename: safeName,
|
|
371
|
+
expectedSizeBytes: chosen.size_bytes
|
|
372
|
+
});
|
|
334
373
|
// files.download() resolves to a plain Response on this SDK version - no
|
|
335
374
|
// writeToFile() helper (see file header). Read the bytes and write them ourselves.
|
|
336
375
|
const response = await client.beta.files.download(chosen.id, {
|
|
337
376
|
betas: [MANAGED_AGENTS_BETA]
|
|
338
377
|
});
|
|
339
378
|
const arrayBuffer = await response.arrayBuffer();
|
|
379
|
+
const downloadedBytes = arrayBuffer.byteLength;
|
|
380
|
+
logTask({
|
|
381
|
+
tool: name,
|
|
382
|
+
status: "download_completed",
|
|
383
|
+
sessionId,
|
|
384
|
+
fileId: chosen.id,
|
|
385
|
+
downloadedBytes
|
|
386
|
+
});
|
|
387
|
+
logTask({ tool: name, status: "saving_file", sessionId, destPath, outputDir });
|
|
340
388
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
341
389
|
fs.writeFileSync(destPath, Buffer.from(arrayBuffer));
|
|
390
|
+
const savedBytes = fs.statSync(destPath).size;
|
|
391
|
+
logTask({
|
|
392
|
+
tool: name,
|
|
393
|
+
status: "file_saved",
|
|
394
|
+
sessionId,
|
|
395
|
+
destPath,
|
|
396
|
+
savedBytes,
|
|
397
|
+
bytesMatch: savedBytes === downloadedBytes
|
|
398
|
+
});
|
|
342
399
|
const downloadUrl = `${publicUrlBase.replace(/\/$/, "")}/${encodeURIComponent(safeName)}`;
|
|
343
400
|
logTask({
|
|
344
401
|
tool: name,
|
|
345
402
|
status: "success",
|
|
346
403
|
sessionId,
|
|
347
404
|
filename: safeName,
|
|
405
|
+
destPath,
|
|
348
406
|
downloadUrl,
|
|
349
407
|
durationMs: Date.now() - startedAt
|
|
350
408
|
});
|
|
@@ -355,6 +413,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
355
413
|
ready: true,
|
|
356
414
|
status: "idle",
|
|
357
415
|
stopReason: "end_turn",
|
|
416
|
+
agentMessage: agentMessagePreview,
|
|
358
417
|
filename: safeName,
|
|
359
418
|
savedTo: destPath,
|
|
360
419
|
downloadUrl
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundai/tb-ppt-mgagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "MCP server that hands a presentation outline to the Traffic Builders PowerPoint Managed Agent, then retrieves the finished .pptx",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"bin": {
|