Tool call's `explanation` is misleading due to truncated arguments
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Version: 1.137.0-insider (user setup)
Commit: de8cc55dae905582f191fdcfb6dff8c811a743c4
Date: 2026-09-04T15:53:39Z
Electron: 42.10.0
ElectronBuildId: 15109253
Chromium: 148.0.7778.280
Node.js: 24.18.1
V8: 14.8.178.38-electron.0
@github/copilot: 1.0.83-2
@github/copilot-sdk: 1.0.13-preview.4
OS: Windows_NT x64 10.0.19045
- Feature (e.g. agent/edit/ask mode): Agent
- Selected model (e.g. GPT 4.1, Claude 3.7 Sonnet): Opus 5
- Logs:
Steps to Reproduce:
1. Have the agent working on one github issue
2. Ask it to check another issue to see if it relates and if it does, add some context to that other issue from what we've learned during this issue's investigation
3. When it goes to add the comment and the UI tries to get our permission, the `explaination` is wrong -- mentioning the original issue instead of the one it is actually trying to update
Reviewing the
```
2026-09-06 08:50:04.026 [info] request done: requestId: [c498d26d-4e9d-4657-8c59-594c6a1b1a21] model deployment ID: []
2026-09-06 08:50:04.027 [info] ccreq:ec043aab.copilotmd | success | gpt-4o-mini-2024-07-18 | 543ms | [copilotLanguageModelWrapper]
```
And the issue is thta the full tool call is being `[truncated]` by the mini agent and the 'issue_code' is way down the line on the tool call so while it is terribly relevant, it isn't known to the mini agent trying to come up with the explaination of why the tool call needs permission.
I almost didn't approve it thinking it was going to post the comment to the wrong issue because of the explanation.
One thought -- truncate long field values rather than the full argument? Or some how sort the json before handle so relevant fields appear first so they won't get truncated? 🤔
```
You assess what one tool call does for a code-editing AI agent, and how risky it is.
The tool may edit files, read files, fetch data, or perform some other action.
Reply with STRICT JSON only (no prose, no markdown fences):
{
"risk": "green" | "orange" | "red",
"explanation": ""
}
Rules for "risk" — apply in order; take the FIRST match:
1. permanently destroys source code or user data with no recovery
(irrecoverable deletion, wiping a database, unrecoverable overwrite) -> red
2. executes code downloaded on the fly from an arbitrary or untrusted URL -> red
3. installs a package or dependency from a registry (npm/pip/cargo/gem/etc.) —
pulls untrusted third-party code, a common supply-chain attack vector -> red
4. sends data to a remote server or changes remote state (POST/PUT, upload, deploy) -> orange
5. modifies local files or workspace state (edits, creates, reversible deletes) -> orange
6. otherwise (reads files, lists, searches, fetches public read-only data) -> green
Read-only operations are always GREEN. Editing or creating a workspace file is
ORANGE (reversible via undo or version control), never red. RED is reserved for
actions whose effects cannot be undone OR that execute untrusted third-party code.
Installing a package is RED even from a normal registry, because it pulls
untrusted third-party code onto this machine — a supply-chain risk regardless of
whether the package manager runs install scripts.
Examples:
read a file's contents -> green
list files in a directory -> green
search the workspace for a symbol -> green
fetch a public web page (GET) -> green
edit an existing source file -> orange
create a new file in the workspace -> orange
POST data to an external API -> orange
install a package -> red (pulls untrusted third-party code)
wipe a database table -> red
run code from an untrusted URL -> red
Write "explanation" in this exact shape:
- green : " ." e.g. "Reads the contents of package.json."
- orange: " — ." e.g. "Edits src/app.ts — changes workspace source."
- red : " — ." e.g. "Deletes src/app.ts — permanently removes source." or "Installs lodash — pulls untrusted third-party code."
Strict explanation rules:
- Cite the ACTUAL files, paths, URLs, or values from the arguments below.
- Never use generic phrases like "may have side effects". Always name WHAT is read or changed.
- Plain prose. No quotes around the sentence. No markdown fences.
Tool: Add comment to issue or pull request (id: mcp_github_mcp_se_add_issue_comment)
Description: Add a comment and/or reaction to a specific issue or issue comment in a GitHub repository. Use this tool with pull requests as well (in this case pass pull request number as issue_number), but only if user is not asking specifically to add or react to review comments. At least one of body or reaction is required.
Arguments (JSON): {"body":"Some context from digging around #686 — I have a leading hypothesis, though I can't run the app so this needs one breakpoint to confirm.\n\n## The likely mechanism: restoring the highlight is indistinguishable from the rep picking a call\n\nThe call list grid binds row selection to a full call-selection event:\n\n```js\n// src/js/callList.js L81\nchange: gridRowSelected,\n\n// L162-173\nfunction gridRowSelected(selectedID) {\n var theGrid = $(\"#callListGrid\").data(\"kendoGrid\");\n if (!theGrid.dataSource.data().length) return;\n var theRowData = theGrid.dataItem(theGrid.select());\n event_callListDidSelectNewCall(theRowData); // <-- loads the call, order header, memos\n}\n```\n\nThree different code paths call `theGrid.select(...)` purely to *restore the visual highlight* after a refresh — and Kendo's `select()` fires `change`, so each one is indistinguishable from the rep clicking a row:\n\n- `selectFirstRowOfGrid()` (L699) — `theGrid.select(firstRow)`\n- `selectSelectedCallRowOfGrid()` (L756) — `theGrid.select(matchedRow)`\n- the Enter-key handler (L185) — calls `grid.select(theRow)` **and** `selectedCall_SetCall(theRowData)`, which suggests the original author was unsure whether `change` fires here\n\n## Why it lands on the *first* call specifically\n\n`selectSelectedCallRowOfGrid()` ends with (L799):\n\n```js\nselectFirstRowOfGrid(); // made it to here. Means the selected call is NOT in the call list, as it was deleted, etc.\n```\n\nWhich is exactly your situation — you just cancelled the order on that call, so it's no longer in the list. The restore looks for your call, doesn't find it, falls back to the first row, and `select()` turns that fallback into a real call selection.\n\nThat also explains your \"*maybe the selected call from before I'm not sure*\": **both** branches of the same function can fire, so sometimes you'd get the first row and sometimes the previously selected call, depending on whether the old call was still in the refresh...[truncated]
```
response
```
{
"risk": "orange",
"explanation": "Adds a comment to issue #686 — changes remote state."
}
```
Contributor guide
Assessment
This issue has not been assessed yet.