Skip to content

Commit 4e404e0

Browse files
committed
fix: stop recommending automatic Java launch retries
1 parent df43dc1 commit 4e404e0

6 files changed

Lines changed: 253 additions & 37 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1017,7 +1017,7 @@
10171017
{
10181018
"name": "debug_java_application",
10191019
"displayName": "Debug Java Application",
1020-
"modelDescription": "Launch or attach to a Java application in debug mode with automatic compilation and classpath resolution. The tool handles building the project, resolving dependencies, starting the JVM with JDWP enabled, and auto-attaching the VS Code debugger. Use this as the first step to establish a debug session. The debug process runs in the background until stopped. Example usage: Debug a main class ('com.example.Main'), a JAR file ('target/app.jar'), or with program arguments (['--port=8080']).",
1020+
"modelDescription": "Launch or attach to a Java application in debug mode with automatic compilation and classpath resolution. The tool handles building the project, resolving dependencies, starting the JVM with JDWP enabled, and auto-attaching the VS Code debugger. Use this as the first step to establish a debug session. The debug process runs in the background until stopped. After the first failure or timeout, do not automatically retry or relaunch through terminal commands. Diagnose and report the result. A timeout means startup is unconfirmed; check session status once if needed, without polling or stopping the original launch. A new attempt requires an identified cause to be fixed or an explicit user retry request; check for an existing session first. Example usage: Debug a main class ('com.example.Main'), a JAR file ('target/app.jar'), or with program arguments (['--port=8080']).",
10211021
"toolReferenceName": "debugJavaApplication",
10221022
"tags": [
10231023
"java",

resources/instruments/javaDebugContext.instructions.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,8 @@ For Java run/launch/debug/inspection requests, prefer the Java debug language mo
1313

1414
If both apply (e.g. "launch and break on entry of `Main.foo`"), load `java-launch-troubleshooting` first, then `java-debug-inspection` after the session is active.
1515

16-
Fall back to `run_in_terminal` only when `debug_java_application` returns "Java Language Server not ready" or "project not detected".
16+
After the first launch failure or timeout, do not automatically retry `debug_java_application` or relaunch through terminal commands, including when Java Language Server is not ready or the project is not detected. Report the result and diagnose the cause.
17+
18+
A timeout means startup is unconfirmed, not necessarily failed. You may check `get_debug_session_info` once and inspect existing terminal output; do not enter a polling loop or terminate the original launch just because the wait expired.
19+
20+
Only start a new launch attempt after fixing an identified cause or when the user explicitly requests a retry. Check for an existing session first and do not replace it without explicit restart intent.

resources/skills/java-debug-inspection/SKILL.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ These language model tools are contributed by the `Debugger for Java` extension
5353
- The program is a non-Java language → do not load this skill
5454
- The user is editing source code without an active debug session → do nothing
5555

56-
## Fallback
56+
## Failure handling
5757

58-
If a tool returns "Java Language Server not ready" or repeats the same error twice, report the raw error to the user and stop calling debug tools for the current turn. Do not retry more than twice.
58+
After the first failed inspection or control operation, report the error and diagnose its cause rather than automatically repeating the failed operation. Read-only diagnosis is allowed, but do not enter a polling loop.
59+
60+
Do not relaunch the application or fall back to terminal launch commands to recover from an inspection error. For launch failures or timeouts, follow `java-launch-troubleshooting`: a new launch attempt requires an identified cause to be fixed or an explicit user retry request, with an existing-session check first.

resources/skills/java-launch-troubleshooting/SKILL.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ These language model tools are contributed by the `Debugger for Java` extension
2727
1. **Confirm intent.** Is the user trying to *run / start / launch / stop* a Java program (use this skill) or just edit code (do not load this skill)?
2828
2. **Check existing session.** Call `get_debug_session_info` first. If a session is already running for the target, do not launch a second one.
2929
3. **Launch.** Call `debug_java_application` with `target` = the fully qualified main class or JAR, and `workspacePath` = the project root containing `pom.xml`, `build.gradle`, or `.classpath`. Let `skipBuild` default to `false` so the tool handles compilation.
30-
4. **Read the error.** If `debug_java_application` fails, the error message is structured (mainClass missing, classpath unresolved, build failure with line number). Use it to suggest a fix — do not retry with `run_in_terminal`.
30+
4. **Stop on the first failure or timeout.** Report the returned result and diagnose the cause. Do not automatically retry `debug_java_application` or relaunch through `run_in_terminal`. A timeout means startup is unconfirmed, not necessarily failed; follow the failure-handling rules below.
3131
5. **Stop when done.** When the user says "stop", "kill it", or has the answer they need, call `stop_debug_session`.
3232

3333
## Common Failure Modes
@@ -45,6 +45,10 @@ These language model tools are contributed by the `Debugger for Java` extension
4545
- The user is already inside a live debug session and wants to inspect variables, evaluate expressions, walk the stack, step, or set / remove breakpoints → use `java-debug-inspection` instead, do not re-launch
4646
- The program is a non-Java language → do not load this skill
4747

48-
## Fallback
48+
## Failure handling
4949

50-
If `debug_java_application` returns `Java Language Server not ready` or repeats the same error twice, fall back to `run_in_terminal` with the appropriate `mvn` or `gradle` command and report the raw output to the user. Do not retry the debug tool more than twice.
50+
After the first launch failure or timeout, stop automatic launch attempts, including when Java Language Server is not ready or the project is not detected. Do not use `run_in_terminal`, `mvn`, `gradle`, or raw `java` commands to bypass this rule.
51+
52+
You may inspect existing errors and terminal output. After a timeout, you may call `get_debug_session_info` once to check whether the original launch has become active. Do not enter a polling loop or terminate the original launch merely because the wait expired.
53+
54+
A new launch attempt is allowed only after fixing an identified cause or when the user explicitly requests a retry. Before that attempt, check for an existing session; do not replace an active session without explicit restart intent.

src/languageModelTool.ts

Lines changed: 20 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,13 @@ const CONSTANTS = {
5858
MAX_FILE_SEARCH_DEPTH: 10
5959
};
6060

61+
const LAUNCH_FAILURE_GUIDANCE = '\n\nDo not automatically retry debug_java_application or start the program again '
62+
+ 'through a terminal command. Report the result and diagnose the cause first. '
63+
+ 'After a timeout, you may check get_debug_session_info once and inspect existing terminal output; '
64+
+ 'do not enter a polling loop or stop the original launch just because the wait expired. '
65+
+ 'Only start a new attempt after fixing an identified cause or when the user explicitly requests a retry. '
66+
+ 'Before a new attempt, check whether the original launch has become active to avoid replacing it.';
67+
6168
// ----------------------------------------------------------------------------
6269
// Process-wide context probed lazily on first use. The value is constant for
6370
// the VS Code session lifetime, so we cache it.
@@ -131,7 +138,8 @@ export function registerLanguageModelTool(
131138
new vscode.LanguageModelTextPart(
132139
`Java No-Config Debug is disabled by ${ENABLE_NO_CONFIG_DEBUG}. `
133140
+ "To use this tool, enable that setting, reload VS Code, and recreate existing terminals. "
134-
+ "Standard Java launch/attach debugging remains available.",
141+
+ "Standard Java launch/attach debugging remains available."
142+
+ LAUNCH_FAILURE_GUIDANCE,
135143
),
136144
]);
137145
}
@@ -152,18 +160,18 @@ export function registerLanguageModelTool(
152160

153161
try {
154162
const result = await debugJavaApplication(options.input, token, guard);
155-
if (!result.success) {
156-
outcome = result.status === 'timeout' ? 'timeout' : 'failure';
157-
errorCategory = result.success ? undefined : classifyError(result.message);
158-
} else if (result.status === 'timeout') {
163+
if (result.status === 'timeout') {
159164
outcome = 'timeout';
160165
errorCategory = 'timeout';
166+
} else if (!result.success) {
167+
outcome = 'failure';
168+
errorCategory = classifyError(result.message);
161169
}
162170

163171
// Format the message for AI - use simple text, not JSON
164172
const message = result.success
165173
? `✓ ${result.message}`
166-
: `✗ ${result.message}`;
174+
: `✗ ${result.message}${LAUNCH_FAILURE_GUIDANCE}`;
167175

168176
// Return result in the expected format - simple text part
169177
return new (vscode as any).LanguageModelToolResult([
@@ -177,7 +185,7 @@ export function registerLanguageModelTool(
177185
const errorMessage = error instanceof Error ? error.message : String(error);
178186

179187
return new (vscode as any).LanguageModelToolResult([
180-
new (vscode as any).LanguageModelTextPart(`✗ Debug failed: ${errorMessage}`)
188+
new (vscode as any).LanguageModelTextPart(`✗ Debug failed: ${errorMessage}${LAUNCH_FAILURE_GUIDANCE}`)
181189
]);
182190
} finally {
183191
recordToolInvocation({
@@ -417,18 +425,8 @@ async function debugJavaApplication(
417425
status: 'timeout',
418426
message: `⏳ Debug session not yet detected for ${targetInfo} after `
419427
+ `${CONSTANTS.SESSION_WAIT_TIMEOUT / 1000} seconds.\n\n`
420-
+ `This is often transient — the JVM may still be starting up (large `
421-
+ `projects, cold class-loading, or remote workspaces can need additional `
422-
+ `time). Telemetry shows that retrying a timed-out launch succeeds for `
423-
+ `the majority of cases.\n\n`
424-
+ `Recommended next actions (in order):\n`
425-
+ `1. Call debug_java_application again — most timeout cases recover on retry.\n`
426-
+ `2. Call get_debug_session_info() to check whether the session has since `
427-
+ `become active.\n`
428-
+ `3. If retrying still times out, inspect terminal '${terminal.name}' for `
429-
+ `compilation errors, ClassNotFoundException, NoClassDefFoundError, or `
430-
+ `other startup failures.\n`
431-
+ `4. Verify the target class name and classpath are correct, then retry.`
428+
+ `Startup is unconfirmed, not necessarily failed. The original command may `
429+
+ `still be running in terminal '${terminal.name}'.`
432430
+ `${warningNote}`,
433431
terminalName: terminal.name
434432
});
@@ -480,20 +478,12 @@ async function debugJavaApplication(
480478
guard?.markOutcomeRecorded();
481479

482480
return {
483-
success: true,
481+
success: false,
484482
status: 'timeout',
485483
message: `⏳ Debug command sent for ${targetInfo}; session not yet detected within `
486484
+ `${CONSTANTS.SMART_POLLING_MAX_WAIT / 1000} seconds.\n\n`
487-
+ `This is often transient — the application may still be starting in terminal `
488-
+ `'${terminal.name}'. Telemetry shows that retrying or polling for status is more `
489-
+ `likely to succeed than treating this as a permanent failure.\n\n`
490-
+ `Recommended next actions (in order):\n`
491-
+ `1. Call get_debug_session_info() to check whether the session has since become active.\n`
492-
+ `2. Call debug_java_application again — most timeout cases recover on retry. `
493-
+ `In the input arguments, set "waitForSession": true (JSON object syntax) to `
494-
+ `extend the wait window for slow-starting apps.\n`
495-
+ `3. If retrying still times out, inspect terminal '${terminal.name}' for compilation `
496-
+ `errors or startup failures, then retry.${warningNote}`,
485+
+ `Startup is unconfirmed, not necessarily failed. The original command may `
486+
+ `still be running in terminal '${terminal.name}'.${warningNote}`,
497487
terminalName: terminal.name
498488
};
499489
}

0 commit comments

Comments
 (0)