Skip to content

Commit a6c36b4

Browse files
committed
chore: refine capture output
1 parent 789cc5b commit a6c36b4

File tree

4 files changed

+67
-49
lines changed

4 files changed

+67
-49
lines changed

agents.md

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ This is a VS Code extension that integrates with GitHub Copilot to provide debug
3232
- **Extension entry point**: `src/extension.ts` - Main activation logic and tool registration
3333
- **Language Model Tools**: Classes implementing VS Code's `LanguageModelTool` interface
3434
- `StartDebuggerTool` - Thin wrapper; delegates validation & launch resolution to `startDebuggingAndWaitForStop`
35-
- `WaitForBreakpointTool` - Waits for breakpoint hits using Debug Adapter Protocol monitoring
3635
- `GetVariablesTool` - Retrieves all variables from active debug sessions using DAP
3736
- `ExpandVariableTool` - Expands specific variables to show detailed contents and immediate children
3837
- **Tool registration**: Registers tools with VS Code's language model system via `vscode.lm.registerTool()`
@@ -50,7 +49,6 @@ This is a VS Code extension that integrates with GitHub Copilot to provide debug
5049

5150
- `src/extension.ts` - Main extension logic, activation, and tool registration only
5251
- `src/startDebuggerTool.ts` - StartDebuggerTool class and interface
53-
- `src/waitForBreakpointTool.ts` - WaitForBreakpointTool class and interface (requires debug-tracker-vscode)
5452
- `src/debugUtils.ts` - Shared DAP interfaces, types, and DAPHelpers utility class
5553
- `src/getVariablesTool.ts` - GetVariablesTool class and interface
5654
- `src/expandVariableTool.ts` - ExpandVariableTool class and interface
@@ -61,19 +59,11 @@ This is a VS Code extension that integrates with GitHub Copilot to provide debug
6159

6260
## Extension Configuration
6361

64-
The extension contributes language model tools that allow Copilot to interact with VS Code's debugging system:
65-
66-
- **`set_breakpoint`** - Sets breakpoints by specifying file path and line number
67-
- **`start_debugger`** - Starts debugging sessions with optional configuration name
68-
- **`wait_for_breakpoint`** - Waits for the debugger to hit a breakpoint or stop execution
69-
- **`get_variables`** - Retrieves all variables from the current debug session when stopped
70-
- **`expand_variable`** - Expands a specific variable to show its detailed contents and immediate child properties
71-
72-
Tools are automatically available to Copilot when the extension is active.
62+
The extension contributes language model tools that allow Copilot to interact with VS Code's debugging system. Tools are automatically available when the extension is active.
7363

7464
### Breakpoint Features
7565

76-
All breakpoint-related tools (`start_debugger` and `resume_debug_session`) support advanced breakpoint configurations:
66+
All breakpoint-related tools (`startDebugSessionWithBreakpoints` and `resumeDebugSession`) support advanced breakpoint configurations:
7767

7868
- **Conditional Breakpoints**: Set `condition` to specify an expression that must evaluate to true for the breakpoint to trigger
7969
- Example: `condition: "$i -ge 3"` (PowerShell) or `condition: "x > 5"` (JavaScript)
@@ -88,7 +78,7 @@ All three properties are optional and can be combined with basic breakpoints tha
8878

8979
### Workspace Folder Semantics
9080

91-
`start_debugger` requires a `workspaceFolder` parameter that must be an absolute path exactly matching one of the open workspace folder roots (`workspace.workspaceFolders[].uri.fsPath`).
81+
`startDebugSessionWithBreakpoints` requires a `workspaceFolder` parameter that must be an absolute path exactly matching one of the open workspace folder roots (`workspace.workspaceFolders[].uri.fsPath`).
9282

9383
Simplifications implemented:
9484

@@ -119,16 +109,6 @@ Example workspace setting:
119109

120110
You can simulate startup delay via a `preLaunchTask` (e.g. `sleep-build-delay`) in `launch.json`. The test suite uses this with `Run timeoutTest.js` to validate timeout behavior.
121111

122-
## Prerequisites
123-
124-
This extension requires the **debug-tracker-vscode** extension to be installed for the `wait_for_breakpoint` tool to function:
125-
126-
1. **Automatic Installation**: The extension will attempt to auto-install if not present
127-
2. **Manual Installation**: Install from VS Code marketplace: `mcu-debug.debug-tracker-vscode`
128-
3. **Command**: Use Quick Open (`Ctrl+P`) and search for "debug-tracker-vscode"
129-
130-
The debug tracker extension provides API services for monitoring debug sessions and is required for breakpoint waiting functionality.
131-
132112
## Implementation Notes
133113

134114
- When adding new tools, define the interface in `package.json` under `languageModelTools`
@@ -198,7 +178,7 @@ The debug tracker extension provides API services for monitoring debug sessions
198178

199179
### Promise-based Tool Implementation
200180

201-
- For tools that wait for events (like `wait_for_breakpoint`), return a Promise from `invoke()`
181+
- For tools that wait for events, return a Promise from `invoke()`
202182
- Use proper Promise constructor with resolve/reject for event-driven operations
203183
- Implement cleanup logic in both success and error paths
204184
- Handle race conditions between timeouts and actual events

package.json

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"bugs": {
1515
"url": "https://github.com/dkattan/Copilot-Breakpoint-Debugger/issues"
1616
},
17+
"when": "debugState == 'running'",
1718
"keywords": [
1819
"copilot",
1920
"debug",
@@ -117,10 +118,10 @@
117118
}
118119
},
119120
"languageModelTools": [
120-
{
121-
"name": "start_debugger_with_breakpoints",
121+
{
122+
"name": "startDebugSessionWithBreakpoints",
122123
"displayName": "Start Debugger",
123-
"toolReferenceName": "startDebugger",
124+
"toolReferenceName": "startDebugSessionWithBreakpoints",
124125
"canBeReferencedInPrompt": true,
125126
"userDescription": "Start a debug session, set breakpoints, and wait until a breakpoint is hit. Supports onHit behaviors: break (pause & return), captureAndContinue (collect variables & interpolated log messages then resume automatically), stopDebugging (terminate after hit). Supports serverReady.action types: httpRequest | shellCommand | vscodeCommand (auto-run after readiness trigger). Exact numeric hitCount pauses on that occurrence.",
126127
"modelDescription": "Start a debug session using the configured default launch configuration or an explicitly provided configurationName. Auto-selects sole launch config when none specified and no default setting is present. Each breakpoint can specify an onHit: break (pause), captureAndContinue (non-blocking gather of variables & interpolation of {var} placeholders in logMessage then continue), or stopDebugging (terminate immediately after hit). Supports serverReady with trigger {path+line | pattern | omitted attach} and action.type httpRequest | shellCommand | vscodeCommand. Conditional expressions and exact numeric hitCount only. variableFilter required only for captureAndContinue; omit to capture all locals up to captureMaxVariables.",
@@ -327,11 +328,10 @@
327328
]
328329
}
329330
},
330-
{
331-
"name": "resume_debug_session",
331+
{
332+
"name": "resumeDebugSession",
332333
"displayName": "Resume Debug Session",
333334
"toolReferenceName": "resumeDebugSession",
334-
"when": "debugState == 'running'",
335335
"canBeReferencedInPrompt": true,
336336
"userDescription": "Resume a paused debug session optionally waiting for the next breakpoint. Supports actions (break, capture, stopDebugging) and numeric hitCount shorthand when adding new breakpoints during resume.",
337337
"modelDescription": "Resume execution of the specified debug session. Optionally wait for next stop and set/clear breakpoints before continuing. Each new breakpoint may specify action (break | capture | stopDebugging), conditional expressions, exact numeric hitCount, and logMessage interpolation for capture.",
@@ -404,8 +404,8 @@
404404
]
405405
}
406406
},
407-
{
408-
"name": "get_variables",
407+
{
408+
"name": "getVariables",
409409
"displayName": "Get Variables",
410410
"toolReferenceName": "getVariables",
411411
"canBeReferencedInPrompt": true,
@@ -416,8 +416,8 @@
416416
"properties": {}
417417
}
418418
},
419-
{
420-
"name": "expand_variable",
419+
{
420+
"name": "expandVariable",
421421
"displayName": "Expand Variable",
422422
"toolReferenceName": "expandVariable",
423423
"canBeReferencedInPrompt": true,
@@ -436,8 +436,8 @@
436436
]
437437
}
438438
},
439-
{
440-
"name": "evaluate_expression",
439+
{
440+
"name": "evaluateExpression",
441441
"displayName": "Evaluate Expression",
442442
"toolReferenceName": "evaluateExpression",
443443
"canBeReferencedInPrompt": true,
@@ -460,8 +460,8 @@
460460
]
461461
}
462462
},
463-
{
464-
"name": "stop_debug_session",
463+
{
464+
"name": "stopDebugSession",
465465
"displayName": "Stop Debug Session",
466466
"toolReferenceName": "stopDebugSession",
467467
"canBeReferencedInPrompt": true,

src/session.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,20 @@ const normalizeFsPath = (value: string) => {
3737
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
3838
};
3939

40+
const reorderScopesForCapture = <T extends { name?: string }>(scopes: T[]): T[] => {
41+
const locals: T[] = [];
42+
const others: T[] = [];
43+
for (const scope of scopes) {
44+
const name = scope?.name?.trim();
45+
if (name && /^locals?$/i.test(name)) {
46+
locals.push(scope);
47+
} else {
48+
others.push(scope);
49+
}
50+
}
51+
return [...locals, ...others];
52+
};
53+
4054
/**
4155
* Variables grouped by scope
4256
*/
@@ -2072,8 +2086,10 @@ export const startDebuggingAndWaitForStop = async (
20722086
finalStop.session,
20732087
finalStop.threadId
20742088
);
2089+
const orderedScopes = reorderScopesForCapture(debugContext.scopes ?? []);
2090+
debugContext = { ...debugContext, scopes: orderedScopes };
20752091
const scopeVariables: ScopeVariables[] = [];
2076-
for (const scope of debugContext.scopes ?? []) {
2092+
for (const scope of orderedScopes) {
20772093
const variables = await DAPHelpers.getVariablesFromReference(
20782094
finalStop.session,
20792095
scope.variablesReference

src/startDebuggerTool.ts

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export class StartDebuggerTool
107107
success = false;
108108
}
109109
const providedFilters = stopInfo.hitBreakpoint.variableFilter ?? [];
110+
const hasExplicitFilters = providedFilters.length > 0;
110111
let activeFilters: string[] = [...providedFilters];
111112
const maxAuto = config.captureMaxVariables ?? 40;
112113
const capturedLogs = stopInfo.capturedLogMessages ?? [];
@@ -124,9 +125,14 @@ export class StartDebuggerTool
124125
const names: string[] = [];
125126
const scopesUsed: string[] = [];
126127
for (const scope of scopes) {
127-
const nonTrivialVars = scope.variables?.filter(
128-
(variable) => !isTrivial(variable.name)
129-
);
128+
const nonTrivialVars = scope.variables?.filter((variable) => {
129+
if (isTrivial(variable.name)) {
130+
return false;
131+
}
132+
const isFunction =
133+
(variable.type ?? "").toLowerCase() === "function";
134+
return !isFunction;
135+
});
130136
if (!nonTrivialVars || nonTrivialVars.length === 0) {
131137
continue;
132138
}
@@ -176,14 +182,24 @@ export class StartDebuggerTool
176182
}
177183
}
178184

179-
const truncate = (val: string) => {
180-
const max = 120;
181-
return val.length > max ? `${val.slice(0, max)}…(${val.length})` : val;
185+
const maxValueLength = 100;
186+
const shouldTruncateValues = !hasExplicitFilters;
187+
let truncatedVariables = false;
188+
const formatValue = (val: string) => {
189+
if (!shouldTruncateValues) {
190+
return val;
191+
}
192+
if (val.length > maxValueLength) {
193+
truncatedVariables = true;
194+
return `${val.slice(0, maxValueLength)}…(${val.length})`;
195+
}
196+
return val;
182197
};
183198
const variableStr = flattened
184199
.map((v) => {
185200
const typePart = v.type ? `:${v.type}` : "";
186-
return `${v.name}=${truncate(v.value)} (${v.scope}${typePart})`;
201+
const displayValue = formatValue(v.value);
202+
return `${v.name}=${displayValue} (${v.scope}${typePart})`;
187203
})
188204
.join("; ");
189205
const fileName = summary.file
@@ -221,11 +237,11 @@ export class StartDebuggerTool
221237
const sessionLabel = state.sessionName ?? state.sessionId ?? "unknown";
222238
switch (state.status) {
223239
case "paused":
224-
return `Debugger State: paused on '${sessionLabel}'. Recommended tools: resume_debug_session, get_variables, expand_variable, evaluate_expression, stop_debug_session.`;
240+
return `Debugger State: paused on '${sessionLabel}'. Recommended tools: resumeDebugSession, getVariables, expandVariable, evaluateExpression, stopDebugSession.`;
225241
case "terminated":
226-
return "Debugger State: terminated. Recommended tool: start_debugger_with_breakpoints to begin a new session.";
242+
return "Debugger State: terminated. Recommended tool: startDebugSessionWithBreakpoints to begin a new session.";
227243
case "running":
228-
return `Debugger State: running. (onHit 'captureAndContinue' continued session '${sessionLabel}'). Recommended tools: wait_for_breakpoint or resume_debug_session with new breakpoints.`;
244+
return `Debugger State: running. (onHit 'captureAndContinue' continued session '${sessionLabel}'). Recommended tool: resumeDebugSession with new breakpoints.`;
229245
}
230246
})();
231247

@@ -256,6 +272,12 @@ export class StartDebuggerTool
256272
);
257273
}
258274

275+
if (truncatedVariables) {
276+
guidance.push(
277+
"Tip: Values were truncated to 100 characters. Provide variableFilter to return full values without truncation."
278+
);
279+
}
280+
259281
const guidanceSection =
260282
guidance.length > 0 ? `Guidance:\n- ${guidance.join("\n- ")}` : "";
261283

0 commit comments

Comments
 (0)