Skip to content

nodejs/langchain: add Word @mention (WpxComment) support#312

Open
biswapm wants to merge 2 commits into
mainfrom
pmohapatra/langchain-word-mention
Open

nodejs/langchain: add Word @mention (WpxComment) support#312
biswapm wants to merge 2 commits into
mainfrom
pmohapatra/langchain-word-mention

Conversation

@biswapm

@biswapm biswapm commented May 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Registers the mcp_WordServer MCP server in ToolingManifest.json so the LangChain sample has Word read/reply tools available.
  • Handles NotificationType.WpxComment in agent.ts: extracts the document URL from activity.attachments, asks the LLM to call mcp_WordServer.GetDocumentContent and the Word reply tool (not AddComment), and proactively notifies the @mentioner in their Teams 1:1 chat with the reply text.
  • Adds a LangGraph MemorySaver checkpointer in client.ts keyed by conversation.id so multi-turn comment threads keep their tool-call history.

Notes

  • Proactive Teams notifications require that the user has spoken to the bot in Teams (or installed it) at least once — we store the conversation reference on every message turn and on InstallationUpdate(add).
  • In-memory only (user-key → conversation map, MemorySaver). For production, swap both for a persistent backing store.
  • Drops the truncated Observability-token prefix from the existing preloadObservabilityToken log line — tokens (even partial) should not be logged.

Test plan

  • Build: npm run build in nodejs/langchain/sample-agent
  • DM the agent in Teams once so the conversation reference is stored
  • @mention the agent on a comment in a Word document; verify a reply is posted on the same comment thread
  • Verify the proactive Teams DM arrives in the same 1:1 chat with the reply text
  • @mention from a user who has never DM'd the agent: reply on the document still works, no Teams DM, log shows the "ask them to message once" hint
  • Verify no token values appear in console output

Wires the LangChain sample so that a Word `@mention` on a document comment
flows through `mcp_WordServer` and is answered with a single reply on the
same thread, with an optional proactive Teams DM to the mentioner.

- ToolingManifest.json: register `mcp_WordServer`.
- src/agent.ts:
  - enable `proactive: {}` on `AgentApplication`.
  - track Teams conversations by user key on every message turn and on
    InstallationUpdate(add), so a later WpxComment can be routed back to
    the same 1:1 chat.
  - handle `NotificationType.WpxComment`: extract document URL from
    `activity.attachments`, prompt the LLM to call `GetDocumentContent`
    and the reply tool (not `AddComment`), and proactively notify the
    mentioner in Teams with the reply text.
  - stop printing the truncated Observability token prefix.
- src/client.ts: add a LangGraph `MemorySaver` checkpointer keyed by
  `conversation.id` so multi-turn comment threads keep their tool-call
  history.
<noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 25, 2026 16:40
@biswapm biswapm requested a review from a team as a code owner May 25, 2026 16:40
@github-actions

github-actions Bot commented May 25, 2026

Copy link
Copy Markdown

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

- mcp_MailTools: switch to the v2 endpoint, Tools.ListInvoke.All scope,
  new audience, and add publisher.
- mcp_OneDriveRemoteServer: register so the @mention flow can resolve
  Word documents stored on OneDrive.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@kiwigitops

Copy link
Copy Markdown

The Word notification flow still logs potentially sensitive document data:

  • the full document sharing URL
  • the first 200 characters of the comment text
  • up to 500 characters of the model summary

That is a privacy footgun for a sample that handles Word documents and user comments, especially since this same change removes the Observability token prefix from logs. It would be safer to log only stable metadata such as documentId, initiatingCommentId, attachment count, and whether a URL was present, while keeping document URLs/comment text out of stdout.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds Word comment @mention (NotificationType.WpxComment) handling to the Node.js LangChain sample so the agent can read the referenced Word document via MCP, post a reply on the existing comment thread, and (optionally) send a proactive Teams 1:1 message back to the mentioner. Also introduces conversation-scoped LangGraph checkpointing to preserve tool-call history across multi-turn threads.

Changes:

  • Register mcp_WordServer in the sample’s ToolingManifest.json.
  • Add WpxComment notification handling in src/agent.ts, including proactive Teams DM routing based on stored conversation references.
  • Add a process-wide LangGraph MemorySaver checkpointer in src/client.ts, keyed by conversation.id via thread_id.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 6 comments.

File Description
nodejs/langchain/sample-agent/ToolingManifest.json Registers the Word MCP server for tool discovery/auth.
nodejs/langchain/sample-agent/src/client.ts Adds LangGraph MemorySaver checkpointer support keyed by conversation thread.
nodejs/langchain/sample-agent/src/agent.ts Implements NotificationType.WpxComment flow + proactive Teams DM routing and removes token-prefix logging.

Comment on lines +15 to +16
"scope": "Tools.ListInvoke.All",
"audience": "c2d0c2b6-8013-4346-9f8b-b81d3b754a29",
Comment on lines +21 to +27
function userKeysFor(from: any): string[] {
if (!from) return [];
const keys = new Set<string>();
if (from.aadObjectId) keys.add(`aad:${String(from.aadObjectId).toLowerCase()}`);
if (from.id) keys.add(`id:${String(from.id).toLowerCase()}`);
if (from.name) keys.add(`name:${String(from.name).toLowerCase()}`);
return [...keys];
Comment on lines +23 to +26
const keys = new Set<string>();
if (from.aadObjectId) keys.add(`aad:${String(from.aadObjectId).toLowerCase()}`);
if (from.id) keys.add(`id:${String(from.id).toLowerCase()}`);
if (from.name) keys.add(`name:${String(from.name).toLowerCase()}`);
Comment on lines +16 to +20
// Maps a user "key" (aadObjectId / id / name) → proactive conversation ID, so
// the WpxComment handler can post a Teams DM back to whichever user @mentioned
// the agent. In-process only — survives the process lifetime; for prod, persist.
const userKeyToConversationId = new Map<string, string>();

Comment on lines +192 to +197
const documentUrl: string | undefined = fileAttachment?.contentUrl;
const documentName: string = fileAttachment?.name ?? 'the document';
const commentText: string = (context.activity as any)?.text ?? '';
const senderName = context.activity.from?.name ?? 'a user';

console.log(`WpxComment received — sender='${senderName}', documentName='${documentName}', documentUrl='${documentUrl ?? '(none)'}', commentText='${commentText.substring(0, 200)}', documentId='${wpx.documentId}', initiatingCommentId='${wpx.initiatingCommentId}'`);
console.log(`WpxComment received — sender='${senderName}', documentName='${documentName}', documentUrl='${documentUrl ?? '(none)'}', commentText='${commentText.substring(0, 200)}', documentId='${wpx.documentId}', initiatingCommentId='${wpx.initiatingCommentId}'`);

try {
const client: Client = await getClient(this.authorization, A365Agent.authHandlerName, context);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants