teams-api 1.5.0 → 1.6.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 (73) hide show
  1. package/README.md +128 -10
  2. package/dist/actions/definitions.d.ts.map +1 -1
  3. package/dist/actions/definitions.js +2 -0
  4. package/dist/actions/definitions.js.map +1 -1
  5. package/dist/actions/file-actions.d.ts.map +1 -1
  6. package/dist/actions/file-actions.js +3 -1
  7. package/dist/actions/file-actions.js.map +1 -1
  8. package/dist/actions/image-description-actions.d.ts +28 -0
  9. package/dist/actions/image-description-actions.d.ts.map +1 -0
  10. package/dist/actions/image-description-actions.js +148 -0
  11. package/dist/actions/image-description-actions.js.map +1 -0
  12. package/dist/actions/message-actions.d.ts.map +1 -1
  13. package/dist/actions/message-actions.js +153 -3
  14. package/dist/actions/message-actions.js.map +1 -1
  15. package/dist/api/chat-service.d.ts +0 -10
  16. package/dist/api/chat-service.d.ts.map +1 -1
  17. package/dist/api/chat-service.js +10 -38
  18. package/dist/api/chat-service.js.map +1 -1
  19. package/dist/api/common.d.ts +4 -0
  20. package/dist/api/common.d.ts.map +1 -1
  21. package/dist/api/common.js +10 -1
  22. package/dist/api/common.js.map +1 -1
  23. package/dist/api/image-description.d.ts +20 -0
  24. package/dist/api/image-description.d.ts.map +1 -0
  25. package/dist/api/image-description.js +77 -0
  26. package/dist/api/image-description.js.map +1 -0
  27. package/dist/audit.d.ts +17 -0
  28. package/dist/audit.d.ts.map +1 -0
  29. package/dist/audit.js +53 -0
  30. package/dist/audit.js.map +1 -0
  31. package/dist/auth/auto-login.d.ts.map +1 -1
  32. package/dist/auth/auto-login.js +1 -3
  33. package/dist/auth/auto-login.js.map +1 -1
  34. package/dist/auth/interactive.d.ts.map +1 -1
  35. package/dist/auth/interactive.js +7 -8
  36. package/dist/auth/interactive.js.map +1 -1
  37. package/dist/auth/token-capture.d.ts.map +1 -1
  38. package/dist/auth/token-capture.js +62 -8
  39. package/dist/auth/token-capture.js.map +1 -1
  40. package/dist/browser-runtime.d.ts +11 -0
  41. package/dist/browser-runtime.d.ts.map +1 -1
  42. package/dist/browser-runtime.js +106 -0
  43. package/dist/browser-runtime.js.map +1 -1
  44. package/dist/conversation-protection.d.ts +21 -0
  45. package/dist/conversation-protection.d.ts.map +1 -0
  46. package/dist/conversation-protection.js +47 -0
  47. package/dist/conversation-protection.js.map +1 -0
  48. package/dist/mcp-auth.d.ts +56 -0
  49. package/dist/mcp-auth.d.ts.map +1 -0
  50. package/dist/mcp-auth.js +207 -0
  51. package/dist/mcp-auth.js.map +1 -0
  52. package/dist/mcp-server.d.ts +1 -0
  53. package/dist/mcp-server.d.ts.map +1 -1
  54. package/dist/mcp-server.js +37 -213
  55. package/dist/mcp-server.js.map +1 -1
  56. package/dist/model-context-protocol-download-content.d.ts +7 -0
  57. package/dist/model-context-protocol-download-content.d.ts.map +1 -0
  58. package/dist/model-context-protocol-download-content.js +90 -0
  59. package/dist/model-context-protocol-download-content.js.map +1 -0
  60. package/dist/server-instructions.d.ts.map +1 -1
  61. package/dist/server-instructions.js +4 -0
  62. package/dist/server-instructions.js.map +1 -1
  63. package/dist/smart-login.d.ts.map +1 -1
  64. package/dist/smart-login.js +3 -3
  65. package/dist/smart-login.js.map +1 -1
  66. package/dist/teams-client.d.ts +10 -1
  67. package/dist/teams-client.d.ts.map +1 -1
  68. package/dist/teams-client.js +82 -23
  69. package/dist/teams-client.js.map +1 -1
  70. package/dist/types.d.ts +54 -0
  71. package/dist/types.d.ts.map +1 -1
  72. package/dist/types.js.map +1 -1
  73. package/package.json +8 -2
package/README.md CHANGED
@@ -381,16 +381,120 @@ Use this only if you already have tokens from another flow or need to avoid brow
381
381
 
382
382
  ### Environment variables
383
383
 
384
- | Variable | Description |
385
- | ----------------------- | --------------------------------------------------------------------- |
386
- | `TEAMS_TOKEN` | Pre-existing skype token |
387
- | `TEAMS_BEARER_TOKEN` | Optional middle-tier bearer token |
388
- | `TEAMS_SUBSTRATE_TOKEN` | Optional Substrate bearer token |
389
- | `TEAMS_REGION` | API region override. Required with `TEAMS_TOKEN`; optional otherwise |
390
- | `TEAMS_EMAIL` | Corporate email. Optional — the server prompts the AI agent if needed |
391
- | `TEAMS_AUTO` | Set to `true` to enable auto-login (macOS + FIDO2) |
392
- | `TEAMS_LOGIN` | Set to `true` to enable interactive browser login |
393
- | `TEAMS_DEBUG_PORT` | Chrome debug port (default: 9222) |
384
+ | Variable | Description |
385
+ | ------------------------------- | -------------------------------------------------------------------------------------- |
386
+ | `TEAMS_TOKEN` | Pre-existing skype token |
387
+ | `TEAMS_BEARER_TOKEN` | Optional middle-tier bearer token |
388
+ | `TEAMS_SUBSTRATE_TOKEN` | Optional Substrate bearer token |
389
+ | `TEAMS_REGION` | API region override. Required with `TEAMS_TOKEN`; optional otherwise |
390
+ | `TEAMS_EMAIL` | Corporate email. Optional — the server prompts the AI agent if needed |
391
+ | `TEAMS_AUTO` | Set to `true` to enable auto-login (macOS + FIDO2) |
392
+ | `TEAMS_LOGIN` | Set to `true` to enable interactive browser login |
393
+ | `TEAMS_DEBUG_PORT` | Chrome debug port (default: 9222) |
394
+ | `TEAMS_EDIT_REPLY_GUARD` | Edit reply guard: `allow` (default), `warn`, or `block`. See below |
395
+ | `TEAMS_AGENT_MARKER` | Agent marker prefix for sent/edited messages (e.g. `Ⓜ`). See below |
396
+ | `TEAMS_DELETE_MODE` | Delete mode: `hard` (default), `soft`, or `block`. See below |
397
+ | `TEAMS_DELETE_TOMBSTONE` | Custom tombstone text for soft-delete mode. See below |
398
+ | `TEAMS_AUDIT_LOG` | Audit logging: `off` (default), `stderr`, or `file:<path>`. See below |
399
+ | `TEAMS_PROTECTED_CONVERSATIONS` | Comma-separated glob patterns of conversations where edit/delete is blocked. See below |
400
+
401
+ #### Agent marker
402
+
403
+ When an AI agent sends or edits messages on behalf of a user, it can be hard to tell which messages were composed by the agent and which by the human. The `TEAMS_AGENT_MARKER` environment variable (or `--agent-marker` CLI flag / `agentMarker` MCP parameter) automatically prepends a configurable string to message content:
404
+
405
+ ```jsonc
406
+ {
407
+ "env": {
408
+ "TEAMS_AGENT_MARKER": "Ⓜ", // or "🤖", "[Bot]", etc.
409
+ },
410
+ }
411
+ ```
412
+
413
+ When set, every `send-message` and `edit-message` call prepends the marker followed by a space to the content. For example, with `TEAMS_AGENT_MARKER=Ⓜ`, sending "Hello world" produces "Ⓜ Hello world".
414
+
415
+ The per-call parameter takes precedence over the environment variable. Pass an empty string to disable the marker for a specific call.
416
+
417
+ #### Edit reply guard
418
+
419
+ When editing a message that already has replies, the original context can be lost — replies may no longer make sense. The `TEAMS_EDIT_REPLY_GUARD` environment variable (or `--reply-guard` CLI flag / `replyGuard` MCP parameter) controls this:
420
+
421
+ | Value | Behavior |
422
+ | ------- | ---------------------------------------------------------------------------------- |
423
+ | `allow` | Edit proceeds normally (default, backward-compatible) |
424
+ | `warn` | Edit proceeds but an annotation is appended: _"⚠️ This message was edited after…"_ |
425
+ | `block` | Edit is refused with an error listing the reply count |
426
+
427
+ The per-call parameter takes precedence over the environment variable.
428
+
429
+ #### Delete mode (soft-delete)
430
+
431
+ Hard-deleting messages removes content permanently, which can be problematic for auditability and conversation flow in group chats. The `TEAMS_DELETE_MODE` environment variable (or `--delete-mode` CLI flag / `deleteMode` MCP parameter) controls how message deletion is handled:
432
+
433
+ | Value | Behavior |
434
+ | ------- | ------------------------------------------------------------------- |
435
+ | `hard` | Permanently delete the message (default, current behavior) |
436
+ | `soft` | Replace message content with a tombstone marker instead of deleting |
437
+ | `block` | Refuse deletion entirely with an error |
438
+
439
+ When using `soft` mode, the message content is replaced with `~~This message was removed by an agent~~` by default. Customize the tombstone text with `TEAMS_DELETE_TOMBSTONE` (or `--delete-tombstone` / `deleteTombstone`):
440
+
441
+ ```jsonc
442
+ {
443
+ "env": {
444
+ "TEAMS_DELETE_MODE": "soft",
445
+ "TEAMS_DELETE_TOMBSTONE": "🗑️ [removed by automation]",
446
+ },
447
+ }
448
+ ```
449
+
450
+ The per-call parameters take precedence over environment variables.
451
+
452
+ #### Audit logging
453
+
454
+ State-modifying actions (edit and delete) can emit structured audit events for compliance and traceability. The `TEAMS_AUDIT_LOG` environment variable controls where events are written:
455
+
456
+ | Value | Behavior |
457
+ | ------------- | ----------------------------------------------------------- |
458
+ | `off` | No audit logging (default) |
459
+ | `stderr` | Write JSON Lines to stderr |
460
+ | `file:<path>` | Append JSON Lines to the specified file (created on demand) |
461
+
462
+ ```jsonc
463
+ {
464
+ "env": {
465
+ "TEAMS_AUDIT_LOG": "file:/var/log/teams-audit.jsonl",
466
+ },
467
+ }
468
+ ```
469
+
470
+ Each event is a single JSON line with the following fields:
471
+
472
+ | Field | Description |
473
+ | ------------------- | ----------------------------------------------------------------------------- |
474
+ | `timestamp` | ISO 8601 timestamp |
475
+ | `action` | `"edit"`, `"delete"`, or `"soft-delete"` |
476
+ | `conversationId` | Conversation thread ID |
477
+ | `conversationLabel` | Human-readable conversation label (topic or 1:1 partner name) |
478
+ | `messageId` | Target message ID |
479
+ | `content` | New content for edits, tombstone text for soft-delete, `null` for hard delete |
480
+
481
+ Audit logging is designed to be silent — errors in the audit pipeline never affect tool execution.
482
+
483
+ #### Protected conversations
484
+
485
+ Some conversations contain sensitive or compliance-relevant information where accidental edits or deletions could be harmful. The `TEAMS_PROTECTED_CONVERSATIONS` environment variable (or `--protected-conversations` CLI flag / `protectedConversations` MCP parameter) blocks edit and delete actions in matching conversations:
486
+
487
+ ```jsonc
488
+ {
489
+ "env": {
490
+ "TEAMS_PROTECTED_CONVERSATIONS": "Incident *,*compliance*,Architecture Decisions",
491
+ },
492
+ }
493
+ ```
494
+
495
+ Patterns are comma-separated and support `*` as a wildcard (matches any characters). Matching is case-insensitive. When a conversation's name matches any pattern, both `edit-message` and `delete-message` throw an error before making any changes — the message is left untouched.
496
+
497
+ The per-call parameter takes precedence over the environment variable, so individual tool invocations can override the configured patterns when needed.
394
498
 
395
499
  ### Available tools
396
500
 
@@ -407,10 +511,23 @@ All MCP tools accept an optional `format` parameter (`concise` or `detailed`). D
407
511
  | `teams_send_message` | Send a message to a conversation |
408
512
  | `teams_get_members` | List members of a conversation |
409
513
  | `teams_get_transcript` | Get a meeting transcript from a recorded conversation |
514
+ | `teams_download_file` | Download message files and inline images |
515
+ | `teams_describe_image` | Describe an inline Teams image with a vision model |
410
516
  | `teams_whoami` | Get the authenticated user's display name |
411
517
 
412
518
  Workflow guidance, tips, and important notes are served automatically via the MCP server's `instructions` field — no separate skill file needed. For the same content on the CLI, run `teams-api guide`.
413
519
 
520
+ ### Image descriptions
521
+
522
+ `teams_describe_image` reuses the existing Teams AMS image download support and sends the image bytes to an OpenAI-compatible vision endpoint. Configure it with `TEAMS_IMAGE_DESCRIPTION_API_KEY` or `OPENAI_API_KEY`. Optional overrides: `TEAMS_IMAGE_DESCRIPTION_MODEL` and `TEAMS_IMAGE_DESCRIPTION_BASE_URL`.
523
+
524
+ Examples:
525
+
526
+ ```bash
527
+ teams-api describe-image --chat "Project Chat" --message-id 1773736076914 --image-index 0
528
+ teams-api describe-image --ams-object-id 0-eaua-d2-877b82634f4e978692f2243d445a6650
529
+ ```
530
+
414
531
  ## API regions
415
532
 
416
533
  The Teams Chat Service URL varies by region. Login-based and debug-session auth detect it automatically. You only need to set `--region` or `TEAMS_REGION` when you are supplying tokens directly or want to force an override:
@@ -423,6 +540,7 @@ The Teams Chat Service URL varies by region. Login-based and debug-session auth
423
540
 
424
541
  ## Known limitations
425
542
 
543
+ - **File attachments are not supported from remote AI hosts** (e.g. Claude.ai). The MCP server runs locally on your machine, so `--file` / `--image` paths must exist on your local filesystem. Cloud-hosted AI clients run in isolated containers and cannot access local paths. Use a local MCP client (Claude Desktop, Cursor, VS Code) or the CLI for file attachments.
426
544
  - Token lifetime is ~24 hours. After expiry, you must re-acquire.
427
545
  - The Teams Chat Service REST API is undocumented and may change without notice.
428
546
  - Auto-login requires macOS, system Chrome, a platform authenticator, and a FIDO2 passkey. On other platforms, use interactive login (`--login`) instead.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/actions/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA2CxD,6DAA6D;AAC7D,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAAwC,CAAC"}
1
+ {"version":3,"file":"definitions.d.ts","sourceRoot":"","sources":["../../src/actions/definitions.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA6CxD,6DAA6D;AAC7D,eAAO,MAAM,OAAO,EAAE,gBAAgB,EAAwC,CAAC"}
@@ -13,6 +13,7 @@ const message_actions_js_1 = require("./message-actions.js");
13
13
  const search_actions_js_1 = require("./search-actions.js");
14
14
  const utility_actions_js_1 = require("./utility-actions.js");
15
15
  const file_actions_js_1 = require("./file-actions.js");
16
+ const image_description_actions_js_1 = require("./image-description-actions.js");
16
17
  // ── Registry ─────────────────────────────────────────────────────────
17
18
  /**
18
19
  * Map-based action registry keyed by action name.
@@ -35,6 +36,7 @@ const actionRegistry = new Map([
35
36
  ["whoami", utility_actions_js_1.whoami],
36
37
  ["get-transcript", utility_actions_js_1.getTranscript],
37
38
  ["download-file", file_actions_js_1.downloadFileAction],
39
+ ["describe-image", image_description_actions_js_1.describeImageAction],
38
40
  ]);
39
41
  /** All registered actions, derived from the registry map. */
40
42
  exports.actions = Array.from(actionRegistry.values());
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/actions/definitions.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAGH,uEAImC;AACnC,6DAO8B;AAC9B,2DAAwE;AACxE,6DAAyE;AACzE,uDAAuD;AAEvD,wEAAwE;AAExE;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAA2B;IACvD,CAAC,oBAAoB,EAAE,2CAAiB,CAAC;IACzC,CAAC,mBAAmB,EAAE,0CAAgB,CAAC;IACvC,CAAC,iBAAiB,EAAE,sCAAY,CAAC;IACjC,CAAC,aAAa,EAAE,oCAAgB,CAAC;IACjC,CAAC,YAAY,EAAE,mCAAe,CAAC;IAC/B,CAAC,cAAc,EAAE,gCAAW,CAAC;IAC7B,CAAC,cAAc,EAAE,gCAAW,CAAC;IAC7B,CAAC,cAAc,EAAE,sCAAiB,CAAC;IACnC,CAAC,gBAAgB,EAAE,wCAAmB,CAAC;IACvC,CAAC,cAAc,EAAE,sCAAiB,CAAC;IACnC,CAAC,iBAAiB,EAAE,yCAAoB,CAAC;IACzC,CAAC,aAAa,EAAE,+BAAU,CAAC;IAC3B,CAAC,QAAQ,EAAE,2BAAM,CAAC;IAClB,CAAC,gBAAgB,EAAE,kCAAa,CAAC;IACjC,CAAC,eAAe,EAAE,oCAAkB,CAAC;CACtC,CAAC,CAAC;AAEH,6DAA6D;AAChD,QAAA,OAAO,GAAuB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC"}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/actions/definitions.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAGH,uEAImC;AACnC,6DAO8B;AAC9B,2DAAwE;AACxE,6DAAyE;AACzE,uDAAuD;AACvD,iFAAqE;AAErE,wEAAwE;AAExE;;;;GAIG;AACH,MAAM,cAAc,GAAG,IAAI,GAAG,CAA2B;IACvD,CAAC,oBAAoB,EAAE,2CAAiB,CAAC;IACzC,CAAC,mBAAmB,EAAE,0CAAgB,CAAC;IACvC,CAAC,iBAAiB,EAAE,sCAAY,CAAC;IACjC,CAAC,aAAa,EAAE,oCAAgB,CAAC;IACjC,CAAC,YAAY,EAAE,mCAAe,CAAC;IAC/B,CAAC,cAAc,EAAE,gCAAW,CAAC;IAC7B,CAAC,cAAc,EAAE,gCAAW,CAAC;IAC7B,CAAC,cAAc,EAAE,sCAAiB,CAAC;IACnC,CAAC,gBAAgB,EAAE,wCAAmB,CAAC;IACvC,CAAC,cAAc,EAAE,sCAAiB,CAAC;IACnC,CAAC,iBAAiB,EAAE,yCAAoB,CAAC;IACzC,CAAC,aAAa,EAAE,+BAAU,CAAC;IAC3B,CAAC,QAAQ,EAAE,2BAAM,CAAC;IAClB,CAAC,gBAAgB,EAAE,kCAAa,CAAC;IACjC,CAAC,eAAe,EAAE,oCAAkB,CAAC;IACrC,CAAC,gBAAgB,EAAE,kDAAmB,CAAC;CACxC,CAAC,CAAC;AAEH,6DAA6D;AAChD,QAAA,OAAO,GAAuB,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"file-actions.d.ts","sourceRoot":"","sources":["../../src/actions/file-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,kBAAkB,EAAE,gBA2GhC,CAAC"}
1
+ {"version":3,"file":"file-actions.d.ts","sourceRoot":"","sources":["../../src/actions/file-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAOH,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,kBAAkB,EAAE,gBA6GhC,CAAC"}
@@ -21,7 +21,9 @@ exports.downloadFileAction = {
21
21
  "Specify the message containing the file(s) via --message-id. " +
22
22
  "Use --output-directory to save files to a specific directory. " +
23
23
  "Without --output-directory, files are saved to a temporary directory. " +
24
- "File contents are returned inline in the response.",
24
+ "Text file contents and images are returned inline in the response. " +
25
+ "Other binary files (PDFs, videos, archives, etc.) are saved to disk only; " +
26
+ "the response reports the local save path.",
25
27
  parameters: [
26
28
  ...conversation_resolution_js_1.conversationParameters,
27
29
  {
@@ -1 +1 @@
1
- {"version":3,"file":"file-actions.js","sourceRoot":"","sources":["../../src/actions/file-actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-actions.js","sourceRoot":"","sources":["../../src/actions/file-actions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Image description action definitions.
3
+ *
4
+ * Actions: describe-image.
5
+ */
6
+ import { type ActionDefinition } from "./formatters.js";
7
+ export declare const ImageDescriptionSourceType: {
8
+ readonly AmsObject: "ams-object";
9
+ readonly Message: "message";
10
+ };
11
+ export type ImageDescriptionSourceType = (typeof ImageDescriptionSourceType)[keyof typeof ImageDescriptionSourceType];
12
+ export interface DescribeImageResult {
13
+ description: string;
14
+ provider: string;
15
+ model: string;
16
+ image: {
17
+ sourceType: ImageDescriptionSourceType;
18
+ amsObjectId: string;
19
+ contentType: string;
20
+ size: number;
21
+ messageId?: string;
22
+ imageIndex?: number;
23
+ width?: number | null;
24
+ height?: number | null;
25
+ };
26
+ }
27
+ export declare const describeImageAction: ActionDefinition;
28
+ //# sourceMappingURL=image-description-actions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-description-actions.d.ts","sourceRoot":"","sources":["../../src/actions/image-description-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,EAAE,KAAK,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAMxD,eAAO,MAAM,0BAA0B;;;CAG7B,CAAC;AAEX,MAAM,MAAM,0BAA0B,GACpC,CAAC,OAAO,0BAA0B,CAAC,CAAC,MAAM,OAAO,0BAA0B,CAAC,CAAC;AAE/E,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE;QACL,UAAU,EAAE,0BAA0B,CAAC;QACvC,WAAW,EAAE,MAAM,CAAC;QACpB,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,CAAC;CACH;AA6ED,eAAO,MAAM,mBAAmB,EAAE,gBAsGjC,CAAC"}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ /**
3
+ * Image description action definitions.
4
+ *
5
+ * Actions: describe-image.
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.describeImageAction = exports.ImageDescriptionSourceType = void 0;
9
+ const image_description_js_1 = require("../api/image-description.js");
10
+ const conversation_resolution_js_1 = require("./conversation-resolution.js");
11
+ exports.ImageDescriptionSourceType = {
12
+ AmsObject: "ams-object",
13
+ Message: "message",
14
+ };
15
+ function resolveImageIndex(value) {
16
+ const imageIndex = value ?? 0;
17
+ if (!Number.isInteger(imageIndex) || imageIndex < 0) {
18
+ throw new Error("imageIndex must be a non-negative integer.");
19
+ }
20
+ return imageIndex;
21
+ }
22
+ function resolveMessageImage(images, imageIndex) {
23
+ const image = images[imageIndex];
24
+ if (!image) {
25
+ throw new Error(`Message image index ${imageIndex} is out of range; the message has ${images.length} image(s).`);
26
+ }
27
+ return image;
28
+ }
29
+ async function resolveImageTarget(client, parameters) {
30
+ const amsObjectId = parameters.amsObjectId;
31
+ if (amsObjectId) {
32
+ return {
33
+ sourceType: exports.ImageDescriptionSourceType.AmsObject,
34
+ amsObjectId,
35
+ };
36
+ }
37
+ const messageId = parameters.messageId;
38
+ if (!messageId) {
39
+ throw new Error("Provide either amsObjectId, or messageId plus chat/to/conversationId.");
40
+ }
41
+ const { conversationId } = await (0, conversation_resolution_js_1.resolveConversationId)(client, parameters);
42
+ const messages = await client.getMessages(conversationId);
43
+ const message = messages.find((candidate) => candidate.id === messageId);
44
+ if (!message) {
45
+ throw new Error(`Message ${messageId} not found in conversation ${conversationId}`);
46
+ }
47
+ if (message.images.length === 0) {
48
+ throw new Error(`Message ${messageId} has no inline images.`);
49
+ }
50
+ const imageIndex = resolveImageIndex(parameters.imageIndex);
51
+ const image = resolveMessageImage(message.images, imageIndex);
52
+ return {
53
+ sourceType: exports.ImageDescriptionSourceType.Message,
54
+ amsObjectId: image.amsObjectId,
55
+ messageId,
56
+ imageIndex,
57
+ width: image.width,
58
+ height: image.height,
59
+ };
60
+ }
61
+ exports.describeImageAction = {
62
+ name: "describe-image",
63
+ title: "Describe Image",
64
+ description: "Describe an inline Teams image using a configured OpenAI-compatible vision model. " +
65
+ "Use amsObjectId directly, or identify a message by chat/to/conversationId plus messageId. " +
66
+ "Set TEAMS_IMAGE_DESCRIPTION_API_KEY or OPENAI_API_KEY before using this tool.",
67
+ parameters: [
68
+ ...conversation_resolution_js_1.conversationParameters,
69
+ {
70
+ name: "messageId",
71
+ type: "string",
72
+ description: "ID of the message containing the image. Required unless amsObjectId is provided.",
73
+ required: false,
74
+ },
75
+ {
76
+ name: "imageIndex",
77
+ type: "number",
78
+ description: "Zero-based index of the inline image within the message (default: 0).",
79
+ required: false,
80
+ default: 0,
81
+ },
82
+ {
83
+ name: "amsObjectId",
84
+ type: "string",
85
+ description: "Direct AMS object ID for an inline Teams image. When provided, conversation and message lookup are skipped.",
86
+ required: false,
87
+ },
88
+ {
89
+ name: "fullSize",
90
+ type: "boolean",
91
+ description: "Download the full-size AMS image before describing it (default: true).",
92
+ required: false,
93
+ default: true,
94
+ },
95
+ {
96
+ name: "prompt",
97
+ type: "string",
98
+ description: "Optional custom instruction for the vision model. Defaults to a concise Teams-context description prompt.",
99
+ required: false,
100
+ },
101
+ ],
102
+ execute: async (client, parameters) => {
103
+ const imageTarget = await resolveImageTarget(client, parameters);
104
+ const fullSize = parameters.fullSize ?? true;
105
+ const imageData = await client.downloadImage(imageTarget.amsObjectId, fullSize);
106
+ const descriptionResult = await (0, image_description_js_1.describeImageWithOpenAiCompatibleVision)({
107
+ imageData: imageData.data,
108
+ contentType: imageData.contentType,
109
+ prompt: parameters.prompt,
110
+ });
111
+ return {
112
+ description: descriptionResult.description,
113
+ provider: descriptionResult.provider,
114
+ model: descriptionResult.model,
115
+ image: {
116
+ ...imageTarget,
117
+ contentType: imageData.contentType,
118
+ size: imageData.size,
119
+ },
120
+ };
121
+ },
122
+ formatConcise: (result) => {
123
+ const descriptionResult = result;
124
+ const lines = [
125
+ "## Image description",
126
+ "",
127
+ descriptionResult.description,
128
+ "",
129
+ `- Provider: ${descriptionResult.provider}`,
130
+ `- Model: ${descriptionResult.model}`,
131
+ `- AMS object ID: ${descriptionResult.image.amsObjectId}`,
132
+ `- Content type: ${descriptionResult.image.contentType}`,
133
+ `- Size: ${descriptionResult.image.size} bytes`,
134
+ ];
135
+ if (descriptionResult.image.messageId) {
136
+ lines.push(`- Message ID: ${descriptionResult.image.messageId}`);
137
+ }
138
+ if (descriptionResult.image.imageIndex !== undefined) {
139
+ lines.push(`- Image index: ${descriptionResult.image.imageIndex}`);
140
+ }
141
+ if (descriptionResult.image.width !== undefined &&
142
+ descriptionResult.image.height !== undefined) {
143
+ lines.push(`- Dimensions: ${descriptionResult.image.width ?? "unknown"} x ${descriptionResult.image.height ?? "unknown"}`);
144
+ }
145
+ return lines.join("\n");
146
+ },
147
+ };
148
+ //# sourceMappingURL=image-description-actions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-description-actions.js","sourceRoot":"","sources":["../../src/actions/image-description-actions.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"message-actions.d.ts","sourceRoot":"","sources":["../../src/actions/message-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,iBAAiB,CAAC;AA0GzB,eAAO,MAAM,WAAW,EAAE,gBAsJzB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,gBAsOzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBA0E/B,CAAC;AAEF,eAAO,MAAM,mBAAmB,EAAE,gBAuCjC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAwD/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,gBAuDlC,CAAC"}
1
+ {"version":3,"file":"message-actions.d.ts","sourceRoot":"","sources":["../../src/actions/message-actions.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAcH,OAAO,EACL,KAAK,gBAAgB,EAGtB,MAAM,iBAAiB,CAAC;AA+GzB,eAAO,MAAM,WAAW,EAAE,gBAsJzB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,gBAqPzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBA0J/B,CAAC;AAIF,eAAO,MAAM,mBAAmB,EAAE,gBAgJjC,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,gBAwD/B,CAAC;AAEF,eAAO,MAAM,oBAAoB,EAAE,gBAuDlC,CAAC"}
@@ -11,6 +11,8 @@ const node_path_1 = require("node:path");
11
11
  const constants_js_1 = require("../constants.js");
12
12
  const formatters_js_1 = require("./formatters.js");
13
13
  const conversation_resolution_js_1 = require("./conversation-resolution.js");
14
+ const audit_js_1 = require("../audit.js");
15
+ const conversation_protection_js_1 = require("../conversation-protection.js");
14
16
  /** Map file extension to MIME content type. */
15
17
  function contentTypeFromExtension(filePath) {
16
18
  const extension = (0, node_path_1.extname)(filePath).toLowerCase();
@@ -312,6 +314,14 @@ exports.sendMessage = {
312
314
  "is automatically fetched and included as a blockquote above your message.",
313
315
  required: false,
314
316
  },
317
+ {
318
+ name: "agentMarker",
319
+ type: "string",
320
+ description: "Prefix to prepend to message content, marking it as agent-generated " +
321
+ '(e.g. "Ⓜ", "🤖", "[Bot]"). ' +
322
+ "Defaults to TEAMS_AGENT_MARKER env var. Omit or set to empty to disable.",
323
+ required: false,
324
+ },
315
325
  ],
316
326
  execute: async (client, parameters) => {
317
327
  let { conversationId, label } = await (0, conversation_resolution_js_1.resolveConversationId)(client, parameters);
@@ -319,7 +329,11 @@ exports.sendMessage = {
319
329
  if (threadMessageId) {
320
330
  conversationId = `${conversationId};messageid=${threadMessageId}`;
321
331
  }
322
- const content = parameters.content ?? "";
332
+ const agentMarker = parameters.agentMarker ??
333
+ process.env.TEAMS_AGENT_MARKER ??
334
+ "";
335
+ const rawContent = parameters.content ?? "";
336
+ const content = agentMarker && rawContent ? `${agentMarker} ${rawContent}` : rawContent;
323
337
  const imagePaths = parameters.image ?? [];
324
338
  const filePaths = parameters.file ?? [];
325
339
  const scheduleAtRaw = parameters.scheduleAt;
@@ -435,14 +449,73 @@ exports.editMessageAction = {
435
449
  "is automatically fetched and included as a blockquote above your message.",
436
450
  required: false,
437
451
  },
452
+ {
453
+ name: "replyGuard",
454
+ type: "string",
455
+ description: 'Controls behavior when the message has replies: "allow" (edit normally), ' +
456
+ '"warn" (edit with annotation appended), "block" (refuse edit). ' +
457
+ 'Defaults to TEAMS_EDIT_REPLY_GUARD env var, or "allow".',
458
+ required: false,
459
+ },
460
+ {
461
+ name: "agentMarker",
462
+ type: "string",
463
+ description: "Prefix to prepend to message content, marking it as agent-generated " +
464
+ '(e.g. "Ⓜ", "🤖", "[Bot]"). ' +
465
+ "Defaults to TEAMS_AGENT_MARKER env var. Omit or set to empty to disable.",
466
+ required: false,
467
+ },
468
+ {
469
+ name: "protectedConversations",
470
+ type: "string",
471
+ description: "Comma-separated glob patterns of conversation names where editing is blocked. " +
472
+ '`*` matches any characters, matching is case-insensitive. Example: "Architecture *,*compliance*". ' +
473
+ "Defaults to TEAMS_PROTECTED_CONVERSATIONS env var. Omit to allow all.",
474
+ required: false,
475
+ },
438
476
  ],
439
477
  execute: async (client, parameters) => {
440
478
  const { conversationId, label } = await (0, conversation_resolution_js_1.resolveConversationId)(client, parameters);
479
+ const protectedPatterns = (0, conversation_protection_js_1.resolveProtectedPatterns)(parameters.protectedConversations);
480
+ const matchedPattern = (0, conversation_protection_js_1.matchProtectedConversation)(label, protectedPatterns);
481
+ if (matchedPattern) {
482
+ throw new Error(`Cannot edit message in "${label}": conversation is protected ` +
483
+ `(matched pattern "${matchedPattern}"). ` +
484
+ `Remove the pattern from TEAMS_PROTECTED_CONVERSATIONS or the protectedConversations parameter to allow editing.`);
485
+ }
441
486
  const messageId = parameters.messageId;
442
- const content = parameters.content;
487
+ const agentMarker = parameters.agentMarker ??
488
+ process.env.TEAMS_AGENT_MARKER ??
489
+ "";
490
+ const rawContent = parameters.content;
491
+ let content = agentMarker ? `${agentMarker} ${rawContent}` : rawContent;
443
492
  const messageFormat = parameters.messageFormat ?? "markdown";
444
493
  const quoteMessageId = parameters.quoteMessageId;
494
+ const replyGuard = parameters.replyGuard ??
495
+ process.env.TEAMS_EDIT_REPLY_GUARD ??
496
+ "allow";
497
+ if (replyGuard !== "allow") {
498
+ const { hasReplies, replyCount } = await client.checkForReplies(conversationId, messageId);
499
+ if (hasReplies) {
500
+ if (replyGuard === "block") {
501
+ throw new Error(`Cannot edit message ${messageId}: it has ${replyCount} ${replyCount === 1 ? "reply" : "replies"}. ` +
502
+ `The reply guard is set to "block". Pass --reply-guard allow to override.`);
503
+ }
504
+ if (replyGuard === "warn") {
505
+ const annotation = `\n\n⚠️ _This message was edited after receiving ${replyCount} ${replyCount === 1 ? "reply" : "replies"}._`;
506
+ content += annotation;
507
+ }
508
+ }
509
+ }
445
510
  const result = await client.editMessage(conversationId, messageId, content, messageFormat, quoteMessageId);
511
+ (0, audit_js_1.emitAuditEvent)({
512
+ timestamp: new Date().toISOString(),
513
+ action: "edit",
514
+ conversationId,
515
+ conversationLabel: label,
516
+ messageId,
517
+ content,
518
+ });
446
519
  return { ...result, conversation: label };
447
520
  },
448
521
  formatConcise: (result) => {
@@ -456,6 +529,7 @@ exports.editMessageAction = {
456
529
  ].join("\n");
457
530
  },
458
531
  };
532
+ const DEFAULT_DELETE_TOMBSTONE = "~~This message was removed by an agent~~";
459
533
  exports.deleteMessageAction = {
460
534
  name: "delete-message",
461
535
  title: "Delete Message",
@@ -472,15 +546,91 @@ exports.deleteMessageAction = {
472
546
  description: "ID of the message to delete",
473
547
  required: true,
474
548
  },
549
+ {
550
+ name: "deleteMode",
551
+ type: "string",
552
+ description: 'Controls how deletion is handled: "hard" (permanently delete, default), ' +
553
+ '"soft" (replace content with tombstone marker), "block" (refuse deletion). ' +
554
+ 'Defaults to TEAMS_DELETE_MODE env var, or "hard".',
555
+ required: false,
556
+ },
557
+ {
558
+ name: "deleteTombstone",
559
+ type: "string",
560
+ description: 'Custom tombstone text used when deleteMode is "soft". ' +
561
+ "Defaults to TEAMS_DELETE_TOMBSTONE env var, or " +
562
+ `"${DEFAULT_DELETE_TOMBSTONE}".`,
563
+ required: false,
564
+ },
565
+ {
566
+ name: "protectedConversations",
567
+ type: "string",
568
+ description: "Comma-separated glob patterns of conversation names where deletion is blocked. " +
569
+ '`*` matches any characters, matching is case-insensitive. Example: "Architecture *,*compliance*". ' +
570
+ "Defaults to TEAMS_PROTECTED_CONVERSATIONS env var. Omit to allow all.",
571
+ required: false,
572
+ },
475
573
  ],
476
574
  execute: async (client, parameters) => {
477
575
  const { conversationId, label } = await (0, conversation_resolution_js_1.resolveConversationId)(client, parameters);
576
+ const protectedPatterns = (0, conversation_protection_js_1.resolveProtectedPatterns)(parameters.protectedConversations);
577
+ const matchedPattern = (0, conversation_protection_js_1.matchProtectedConversation)(label, protectedPatterns);
578
+ if (matchedPattern) {
579
+ throw new Error(`Cannot delete message in "${label}": conversation is protected ` +
580
+ `(matched pattern "${matchedPattern}"). ` +
581
+ `Remove the pattern from TEAMS_PROTECTED_CONVERSATIONS or the protectedConversations parameter to allow deletion.`);
582
+ }
478
583
  const messageId = parameters.messageId;
584
+ const deleteMode = parameters.deleteMode ??
585
+ process.env.TEAMS_DELETE_MODE ??
586
+ "hard";
587
+ if (deleteMode === "block") {
588
+ throw new Error(`Cannot delete message ${messageId}: delete mode is set to "block". ` +
589
+ `Pass --delete-mode hard to override.`);
590
+ }
591
+ if (deleteMode === "soft") {
592
+ const tombstone = parameters.deleteTombstone ??
593
+ process.env.TEAMS_DELETE_TOMBSTONE ??
594
+ DEFAULT_DELETE_TOMBSTONE;
595
+ const result = await client.editMessage(conversationId, messageId, tombstone, "markdown");
596
+ (0, audit_js_1.emitAuditEvent)({
597
+ timestamp: new Date().toISOString(),
598
+ action: "soft-delete",
599
+ conversationId,
600
+ conversationLabel: label,
601
+ messageId,
602
+ content: tombstone,
603
+ });
604
+ return {
605
+ messageId: result.messageId,
606
+ editTime: result.editTime,
607
+ conversation: label,
608
+ softDeleted: true,
609
+ };
610
+ }
479
611
  const result = await client.deleteMessage(conversationId, messageId);
612
+ (0, audit_js_1.emitAuditEvent)({
613
+ timestamp: new Date().toISOString(),
614
+ action: "delete",
615
+ conversationId,
616
+ conversationLabel: label,
617
+ messageId,
618
+ content: null,
619
+ });
480
620
  return { ...result, conversation: label };
481
621
  },
482
622
  formatConcise: (result) => {
483
- const { messageId, conversation } = result;
623
+ const { messageId, conversation, softDeleted, editTime } = result;
624
+ if (softDeleted) {
625
+ return [
626
+ "## Message Soft-Deleted",
627
+ "",
628
+ `- **In:** ${conversation}`,
629
+ `- **Message ID:** ${messageId}`,
630
+ `- **Edit time:** ${editTime}`,
631
+ "- **Mode:** Content replaced with tombstone marker",
632
+ ].join("\n");
633
+ }
484
634
  return [
485
635
  "## Message Deleted",
486
636
  "",