teams-api 1.5.0 → 1.6.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 +128 -10
- package/dist/actions/definitions.d.ts.map +1 -1
- package/dist/actions/definitions.js +2 -0
- package/dist/actions/definitions.js.map +1 -1
- package/dist/actions/file-actions.d.ts.map +1 -1
- package/dist/actions/file-actions.js +3 -1
- package/dist/actions/file-actions.js.map +1 -1
- package/dist/actions/image-description-actions.d.ts +28 -0
- package/dist/actions/image-description-actions.d.ts.map +1 -0
- package/dist/actions/image-description-actions.js +148 -0
- package/dist/actions/image-description-actions.js.map +1 -0
- package/dist/actions/message-actions.d.ts.map +1 -1
- package/dist/actions/message-actions.js +153 -3
- package/dist/actions/message-actions.js.map +1 -1
- package/dist/api/chat-service.d.ts +0 -10
- package/dist/api/chat-service.d.ts.map +1 -1
- package/dist/api/chat-service.js +1 -37
- package/dist/api/chat-service.js.map +1 -1
- package/dist/api/common.d.ts +4 -0
- package/dist/api/common.d.ts.map +1 -1
- package/dist/api/common.js +10 -1
- package/dist/api/common.js.map +1 -1
- package/dist/api/image-description.d.ts +20 -0
- package/dist/api/image-description.d.ts.map +1 -0
- package/dist/api/image-description.js +77 -0
- package/dist/api/image-description.js.map +1 -0
- package/dist/audit.d.ts +17 -0
- package/dist/audit.d.ts.map +1 -0
- package/dist/audit.js +53 -0
- package/dist/audit.js.map +1 -0
- package/dist/auth/auto-login.d.ts.map +1 -1
- package/dist/auth/auto-login.js +1 -3
- package/dist/auth/auto-login.js.map +1 -1
- package/dist/auth/interactive.d.ts.map +1 -1
- package/dist/auth/interactive.js +7 -8
- package/dist/auth/interactive.js.map +1 -1
- package/dist/auth/token-capture.d.ts.map +1 -1
- package/dist/auth/token-capture.js +62 -8
- package/dist/auth/token-capture.js.map +1 -1
- package/dist/browser-runtime.d.ts +11 -0
- package/dist/browser-runtime.d.ts.map +1 -1
- package/dist/browser-runtime.js +106 -0
- package/dist/browser-runtime.js.map +1 -1
- package/dist/conversation-protection.d.ts +21 -0
- package/dist/conversation-protection.d.ts.map +1 -0
- package/dist/conversation-protection.js +47 -0
- package/dist/conversation-protection.js.map +1 -0
- package/dist/mcp-auth.d.ts +56 -0
- package/dist/mcp-auth.d.ts.map +1 -0
- package/dist/mcp-auth.js +207 -0
- package/dist/mcp-auth.js.map +1 -0
- package/dist/mcp-server.d.ts +1 -0
- package/dist/mcp-server.d.ts.map +1 -1
- package/dist/mcp-server.js +37 -213
- package/dist/mcp-server.js.map +1 -1
- package/dist/model-context-protocol-download-content.d.ts +7 -0
- package/dist/model-context-protocol-download-content.d.ts.map +1 -0
- package/dist/model-context-protocol-download-content.js +90 -0
- package/dist/model-context-protocol-download-content.js.map +1 -0
- package/dist/server-instructions.d.ts.map +1 -1
- package/dist/server-instructions.js +4 -0
- package/dist/server-instructions.js.map +1 -1
- package/dist/smart-login.d.ts.map +1 -1
- package/dist/smart-login.js +3 -3
- package/dist/smart-login.js.map +1 -1
- package/dist/teams-client.d.ts +10 -1
- package/dist/teams-client.d.ts.map +1 -1
- package/dist/teams-client.js +82 -23
- package/dist/teams-client.js.map +1 -1
- package/dist/types.d.ts +54 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- 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
|
|
385
|
-
|
|
|
386
|
-
| `TEAMS_TOKEN`
|
|
387
|
-
| `TEAMS_BEARER_TOKEN`
|
|
388
|
-
| `TEAMS_SUBSTRATE_TOKEN`
|
|
389
|
-
| `TEAMS_REGION`
|
|
390
|
-
| `TEAMS_EMAIL`
|
|
391
|
-
| `TEAMS_AUTO`
|
|
392
|
-
| `TEAMS_LOGIN`
|
|
393
|
-
| `TEAMS_DEBUG_PORT`
|
|
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;
|
|
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;
|
|
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,
|
|
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
|
-
"
|
|
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":";AAAA;;;;GAIG;;;AAEH,qCAAmD;AACnD,yCAA0C;AAC1C,qCAAiC;AACjC,6CAAyC;AACzC,mDAA2D;AAE3D,6EAGsC;AAWzB,QAAA,kBAAkB,GAAqB;IAClD,IAAI,EAAE,eAAe;IACrB,KAAK,EAAE,eAAe;IACtB,WAAW,EACT,8CAA8C;QAC9C,oDAAoD;QACpD,sEAAsE;QACtE,+DAA+D;QAC/D,gEAAgE;QAChE,wEAAwE;QACxE,
|
|
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;
|
|
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
|
|
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
|
|
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
|
"",
|