@friendlyrobot/discord-pi-agent 0.13.0 → 0.14.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.
@@ -22,6 +22,7 @@ export declare class AgentService {
22
22
  findModel(provider: string, modelId: string): Model<any> | undefined;
23
23
  createSession(sessionDir: string): Promise<AgentSession>;
24
24
  prompt(text: string): Promise<string>;
25
+ getSkillsSummary(): string;
25
26
  reloadResources(): Promise<string>;
26
27
  getExtensionsSummary(): string;
27
28
  compact(): Promise<string>;
package/dist/index.js CHANGED
@@ -282,13 +282,25 @@ class AgentService {
282
282
  logPrefix: `[agent:${session.sessionId}]`
283
283
  });
284
284
  }
285
+ getSkillsSummary() {
286
+ const result = this.resourceLoader.getSkills();
287
+ const { skills } = result;
288
+ if (skills.length === 0) {
289
+ return "Skills: (none loaded)";
290
+ }
291
+ const names = skills.map((s) => s.name);
292
+ return `Skills (${skills.length}): ${names.join(", ") || "(none)"}`;
293
+ }
285
294
  async reloadResources() {
286
295
  await this.resourceLoader.reload();
287
296
  const extensions = this.resourceLoader.getExtensions().extensions.map((ext) => ext.path);
297
+ const skills = this.resourceLoader.getSkills();
298
+ const skillNames = skills.skills.map((s) => s.name);
288
299
  const agentsFiles = this.resourceLoader.getAgentsFiles().agentsFiles.map((f) => f.path);
289
300
  return [
290
301
  "Resources reloaded.",
291
302
  `Extensions (${extensions.length}): ${extensions.join(", ") || "(none)"}`,
303
+ `Skills (${skills.skills.length}): ${skillNames.join(", ") || "(none)"}`,
292
304
  `AGENTS.md files (${agentsFiles.length}): ${agentsFiles.join(", ") || "(none)"}`
293
305
  ].join(`
294
306
  `);
@@ -657,8 +669,11 @@ function getSessionStatusText(session, promptQueue, extras) {
657
669
  `queue-busy: ${queueStatus.busy}`
658
670
  ];
659
671
  if (extras?.tools && extras.tools.length > 0) {
660
- const toolLines = extras.tools.map((t) => ` ${t.name} - ${t.description}`);
661
- lines.push("", `Tools (${extras.tools.length}):`, ...toolLines);
672
+ const toolNames = extras.tools.map((t) => t.name);
673
+ lines.push("", `Tools (${extras.tools.length}): ${toolNames.join(", ")}`);
674
+ }
675
+ if (extras?.skillsSummary) {
676
+ lines.push("", extras.skillsSummary);
662
677
  }
663
678
  if (extras?.extensionsSummary) {
664
679
  lines.push("", extras.extensionsSummary);
@@ -725,11 +740,13 @@ async function handleCommand(input, ctx) {
725
740
  }
726
741
  const tools = effectiveSession.getAllTools();
727
742
  const extensionsSummary = agentService.getExtensionsSummary();
743
+ const skillsSummary = agentService.getSkillsSummary();
728
744
  return {
729
745
  handled: true,
730
746
  response: getSessionStatusText(effectiveSession, promptQueue, {
731
747
  tools,
732
- extensionsSummary
748
+ extensionsSummary,
749
+ skillsSummary
733
750
  })
734
751
  };
735
752
  }
@@ -870,15 +887,15 @@ var logger5 = createModuleLogger("image-description");
870
887
  async function describeImage(agentService, imageData, mimeType, userText, visionModel) {
871
888
  const session = await agentService.createTemporarySession();
872
889
  await session.setModel(visionModel);
873
- const isPdf = mimeType === "application/pdf";
890
+ const mediaType = getMediaType(mimeType);
874
891
  const imageContent = {
875
892
  type: "image",
876
893
  data: imageData,
877
894
  mimeType
878
895
  };
879
896
  let promptText;
880
- if (isPdf) {
881
- promptText = userText.trim().length > 0 ? `The user sent a PDF document with the following message: "${userText}". Please extract and summarize the text content of this PDF. Be thorough — include all important details, sections, and data from the document.` : "Please extract and summarize the text content of this PDF document. Be thorough — include all important details, sections, data, and key points.";
897
+ if (mediaType === "document") {
898
+ promptText = userText.trim().length > 0 ? `The user sent a document with the following message: "${userText}". Please extract and summarize the text content of this document. Be thorough — include all important details, sections, and data from the document.` : "Please extract and summarize the text content of this document. Be thorough — include all important details, sections, data, and key points.";
882
899
  } else {
883
900
  promptText = userText.trim().length > 0 ? `The user sent this image with the following message: "${userText}". Please describe the image in detail and address any questions from the user's message.` : "Please describe this image in detail. What do you see?";
884
901
  }
@@ -920,6 +937,12 @@ function extractLastAssistantText(session) {
920
937
  }
921
938
  return "";
922
939
  }
940
+ function getMediaType(mimeType) {
941
+ if (mimeType.startsWith("image/")) {
942
+ return "image";
943
+ }
944
+ return "document";
945
+ }
923
946
  function isAssistantMessage(msg) {
924
947
  return typeof msg === "object" && msg !== null && "role" in msg && msg.role === "assistant";
925
948
  }
@@ -1223,9 +1246,24 @@ var MEDIA_ATTACHMENT_EXTENSIONS = [
1223
1246
  ".jpeg",
1224
1247
  ".gif",
1225
1248
  ".webp",
1226
- ".pdf"
1249
+ ".pdf",
1250
+ ".docx",
1251
+ ".doc",
1252
+ ".pptx",
1253
+ ".ppt",
1254
+ ".xlsx",
1255
+ ".xls"
1227
1256
  ];
1228
1257
  var MAX_MEDIA_ATTACHMENT_SIZE = 25 * 1024 * 1024;
1258
+ var OFFICE_MIME_TYPES = new Set([
1259
+ "application/pdf",
1260
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
1261
+ "application/msword",
1262
+ "application/vnd.openxmlformats-officedocument.presentationml.presentation",
1263
+ "application/vnd.ms-powerpoint",
1264
+ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
1265
+ "application/vnd.ms-excel"
1266
+ ]);
1229
1267
  function isMediaAttachment(attachment) {
1230
1268
  const ext = attachment.name?.slice(attachment.name.lastIndexOf(".")).toLowerCase();
1231
1269
  if (!ext || !MEDIA_ATTACHMENT_EXTENSIONS.includes(ext)) {
@@ -1235,7 +1273,7 @@ function isMediaAttachment(attachment) {
1235
1273
  if (!ct) {
1236
1274
  return false;
1237
1275
  }
1238
- return ct.startsWith("image/") || ct === "application/pdf";
1276
+ return ct.startsWith("image/") || OFFICE_MIME_TYPES.has(ct);
1239
1277
  }
1240
1278
  async function readMediaAttachments(message) {
1241
1279
  const attachments = message.attachments;
@@ -1297,6 +1335,21 @@ function parseVisionModelId(visionModelId) {
1297
1335
  modelId: trimmed.substring(slashIndex + 1)
1298
1336
  };
1299
1337
  }
1338
+ function getMediaLabel(filename, mimeType) {
1339
+ if (mimeType === "application/pdf") {
1340
+ return `[PDF: ${filename}]`;
1341
+ }
1342
+ if (mimeType === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" || mimeType === "application/msword") {
1343
+ return `[Word: ${filename}]`;
1344
+ }
1345
+ if (mimeType === "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" || mimeType === "application/vnd.ms-excel") {
1346
+ return `[Excel: ${filename}]`;
1347
+ }
1348
+ if (mimeType === "application/vnd.openxmlformats-officedocument.presentationml.presentation" || mimeType === "application/vnd.ms-powerpoint") {
1349
+ return `[PowerPoint: ${filename}]`;
1350
+ }
1351
+ return `[Image: ${filename}]`;
1352
+ }
1300
1353
  async function resolveMediaAttachments(media, content, currentModel, config, agentService) {
1301
1354
  const modelSupportsVision = currentModel?.input.includes("image") ?? false;
1302
1355
  if (modelSupportsVision) {
@@ -1319,7 +1372,7 @@ async function resolveMediaAttachments(media, content, currentModel, config, age
1319
1372
  const note = `
1320
1373
 
1321
1374
  [User sent media attachment(s): ${names}]
1322
- ` + "(Media vision not configured. Set visionModelId to enable image/PDF understanding.)";
1375
+ ` + "(Media vision not configured. Set visionModelId to enable image/PDF/document understanding.)";
1323
1376
  return { content: content ? content + note : note, images: [] };
1324
1377
  }
1325
1378
  const parsed = parseVisionModelId(config.visionModelId);
@@ -1342,9 +1395,8 @@ async function resolveMediaAttachments(media, content, currentModel, config, age
1342
1395
  }, "describing media with vision model");
1343
1396
  const descriptions = [];
1344
1397
  for (const m of media) {
1345
- const isPdf = m.mimeType === "application/pdf";
1346
1398
  const description = await describeImage(agentService, m.data, m.mimeType, content, visionModel);
1347
- const label = isPdf ? `[PDF: ${m.filename}]` : `[Image: ${m.filename}]`;
1399
+ const label = getMediaLabel(m.filename, m.mimeType);
1348
1400
  descriptions.push(`${label}
1349
1401
  ${description}`);
1350
1402
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@friendlyrobot/discord-pi-agent",
3
- "version": "0.13.0",
3
+ "version": "0.14.1",
4
4
  "description": "Reusable Discord gateway bridge for persistent pi agent sessions",
5
5
  "license": "MIT",
6
6
  "type": "module",