You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 1682-java-tool-ergonomics-prompts-remove-before-merge/20260622-prompts.md
+306Lines changed: 306 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -431,3 +431,309 @@ Ran terminal command: export JAVA_HOME="/Library/Java/JavaVirtualMachines/micro
431
431
432
432
Made changes.
433
433
434
+
### 17:46Prompt
435
+
436
+
Read `copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md` (the plan) to get the context.
437
+
438
+
✅✅Pay very close attention to each **Resolution:** to the questions in `Phase3 — Ignorance reduction: questions to answer before writing code`.
439
+
440
+
Inthis session, we are creating issues of type **Task** as children of Epic https://github.com/github/copilot-sdk/issues/1682 . These issues correspond to the sub-sections in `## Phase 4 — Implementation (the build order)`.
441
+
442
+
I want you to use `gh` to create issues as sub-issues of 1682.
443
+
444
+
-I will dispatch these issues by assigning them to an agent. Leave them unassigned for now.
445
+
446
+
-The description you put in the issues you create is the specification for the work the agent assigned to the issue must do. Therefore, you need to be very specific and targeted when writing the description.
447
+
448
+
-Set the type to **Task**.
449
+
450
+
-Each issue will be worked on and resolved in serial. You can assume:
451
+
452
+
-All issues will operate in this topic branch of `upstream`: `edburns/1682-java-tool-ergonomics`.
453
+
454
+
-The assignee agent has access to the topic branch and, most importantly, to the prompts in the directory `1682-java-tool-ergonomics-prompts-remove-before-merge`, which includes the plan. Therefore, you can instruct the agent to access the plan by reference, you don't need to reference it by value directly in the issue.
455
+
456
+
- The sub-sections of `## Phase 4 — Implementation (the build order)` have essential details for each corresponding **Task**.
457
+
458
+
- Instruct the agent to read the entire plan before working.
459
+
460
+
- Instruct the agent to carefully re-read the relevant sections of the of the plan. ❌❌You can't just say, "read the relevant sections of the plan". ✅✅In the description of the issue, list exactly what sections of the plan apply to this particular issue.
461
+
462
+
-Though the sub-sections of `## Phase4 — Implementation (the build order)` have essential details for each corresponding **Task**, I want you to carefully consider if there additional gating tests you can add so that as the agent proceeds from one task to the next, the likelihood of rework is reduced.
463
+
464
+
### 18:16Response
465
+
466
+
Updated todo list
467
+
468
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#1-1), lines 1 to 100
469
+
470
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#101-101), lines 101 to 200
471
+
472
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#201-201), lines 201 to 300
473
+
474
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#301-301), lines 301 to 400
475
+
476
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#401-401), lines 401 to 500
477
+
478
+
Read [](file:///Users/edburns/workareas/copilot-sdk/1682-java-tool-ergonomics-prompts-remove-before-merge/dd-3018003-ignorance-reduction-for-implementation-plan.md#501-501), lines 501 to 505
479
+
480
+
NowI have the full plan. Let me create the 5 issues (4.1–4.5, skipping 4.6 which is deferred) as sub-issues of #1682.I'll write detailed descriptions with gating tests.
481
+
482
+
Ran terminal command: gh issue create --help 2>&1 | head -40
483
+
484
+
`gh issue create` supports `--parent` and `--type` directly. I'll create each issue with a body file.
485
+
486
+
Created [](file:///tmp/issue-4.1-body.md)
487
+
488
+
Created [](file:///tmp/issue-4.2-body.md)
489
+
490
+
Created [](file:///tmp/issue-4.3-body.md)
491
+
492
+
Created5 todos
493
+
494
+
Created [](file:///tmp/issue-4.4-body.md)
495
+
496
+
Created [](file:///tmp/issue-4.5-body.md)
497
+
498
+
NowI'll create the issues using `gh`:
499
+
500
+
Ran terminal command: cd /Users/edburns/workareas/copilot-sdk && gh issue create \
| 4.4 | [#1761](https://github.com/github/copilot-sdk/issues/1761) | `ToolDefinition.fromObject(Object)` registration API |
543
+
| 4.5 | [#1762](https://github.com/github/copilot-sdk/issues/1762) | E2E integration test with replay proxy |
544
+
545
+
Each issue includes:
546
+
- Explicit list of plan sections to re-read (by section number and title)
547
+
- Instruction to read the full plan before starting
548
+
- Detailed gating tests beyond what the plan specifies (e.g., reflection-based annotation attribute verification in 4.1, handler invocation tests in 4.4)
549
+
- Clear prerequisites (serial dependency chain)
550
+
- Branch and constraint information
551
+
552
+
Updated todo list
553
+
554
+
Made changes.
555
+
556
+
### 18:37 Prompt
557
+
558
+
Consider this text from the plan
559
+
560
+
--------
561
+
562
+
**Question:** What attributes does `@CopilotTool` need?
563
+
564
+
Based on ADR-005 and the C#/langchain4j comparisons:
565
+
566
+
```java
567
+
@Documented
568
+
@Retention(RetentionPolicy.SOURCE) // only needed at compile time for processor
569
+
@Target(ElementType.METHOD)
570
+
@CopilotExperimental
571
+
public @interface CopilotTool {
572
+
/** Tool description (sent to the model). */
573
+
String value();
574
+
575
+
/** Tool name. Defaults to method name converted to snake_case. */
576
+
String name() default "";
577
+
578
+
/** Whether this tool overrides a built-in tool. */
579
+
boolean overridesBuiltInTool() default false;
580
+
581
+
/** Whether to skip permission checks. */
582
+
boolean skipPermission() default false;
583
+
}
584
+
```
585
+
586
+
587
+
------
588
+
589
+
I'm concerned about relying on snake_case here. That's a Python thing. Java uses camelCase.
590
+
591
+
What would be the changes to the overall design if we said camelCase instead of snake_case?
592
+
593
+
### 18:40 Prompt
594
+
595
+
Updated todo list
596
+
597
+
Let me check what naming convention the existing SDK and wire protocol actually use for tool names.
598
+
599
+
Searched for regex `tool.*name` (`**/test/snapshots/tools/*.yaml`), no results
600
+
601
+
Searched for regex `snake_case|snakeCase|toSnakeCase|to_snake` (`**/java/**`), 9 results
602
+
603
+
Searched for regex `DefineTool|define_tool|defineTool` (`**/nodejs/src/**`), 4 results
Every SDK across all languages uses `snake_case` for tool names on the wire. This is the **Copilot CLI / model-facing convention** — it's how the LLM identifies and calls tools in function-calling. It's not language-internal naming; it's a wire protocol identifier.
638
+
639
+
## Impact of switching to `camelCase`
640
+
641
+
If you changed the default conversion to camelCase (or just identity — since Java methods are already camelCase):
642
+
643
+
|Aspect|Impact|
644
+
|--------|--------|
645
+
|**Wire compatibility**|Tool names like `setCurrentPhase` instead of `set_current_phase`.The model still works (it's just a string), but diverges from every other SDK's convention. |
646
+
|**Cross-SDK consistency**|A tool that's `set_current_phase` in Node/Go/.NET/Python/Rust would be `setCurrentPhase` in Java — confusing for multi-SDK teams. |
647
+
| **Snapshot reuse** | Can't share the same test snapshots across SDKs (model expects specific tool names in responses).|
648
+
|**Code change**|Actually simplifies the processor — no case conversion logic needed (identity transform).|
649
+
|**Override tools**|Built-in Copilot tools use `snake_case` (like `grep`).Overriding them already requires explicit `name="grep"`, so no impact there. |
650
+
651
+
## Recommendation
652
+
653
+
Keep `snake_case` as the **default** wire name derivation. The rationale is protocol-level consistency, not Java style:
-The**tool name** sent to the model is `set_current_phase` — idiomatic function-calling protocol.
657
+
-Users can always override with `@CopilotTool(name="whateverTheyWant")`.
658
+
659
+
This is the same pattern Jackson uses:Java fields are camelCase, but `@JsonProperty` / `PropertyNamingStrategies` controls the wire format. The wire convention is independent of the source language.
660
+
661
+
If you still prefer dropping the conversion, the only code changes would be:
662
+
1.Remove the snake_case converter from the processor (4.3).
663
+
2.Update the test in 4.3 that verifies `setCurrentPhase` → `set_current_phase`.
664
+
3.Update the E2E snapshot/test (4.5) tool names.
665
+
666
+
### 18:41Prompt
667
+
668
+
Look at what the agent changed in commit 8b899e15254b2b539ae585c85d1e7c39ef864194 to `java/src/main/java/com/github/copilot/rpc/ToolDefer.java`.It added NONE.
669
+
670
+
Is there a precedent forthisNONE thing in the other languages?
671
+
672
+
### 18:43Response
673
+
674
+
Updated todo list
675
+
676
+
Ran terminal command: git show 8b899e15254b2b539ae585c85d1e7c39ef864194 -- java/src/main/java/com/github/copilot/rpc/ToolDefer.java
Searched for regex `CopilotToolDefer` (`**/dotnet/src/**`), 8 results
685
+
686
+
Searched for regex `defer` (`**/nodejs/src/types.ts`), 4 results
687
+
688
+
Read [](file:///Users/edburns/workareas/copilot-sdk/dotnet/src/CopilotTool.cs#155-155), lines 155 to 170
689
+
690
+
Read [](file:///Users/edburns/workareas/copilot-sdk/java/src/main/java/com/github/copilot/rpc/ToolDefer.java#1-1), lines 1 to 10
691
+
692
+
Read [](file:///Users/edburns/workareas/copilot-sdk/java/src/main/java/com/github/copilot/rpc/ToolDefer.java#20-20), lines 20 to 50
693
+
694
+
**No, there is no precedent for `NONE` in the other languages.**
695
+
696
+
-**.NET**: `CopilotToolDefer` has only `Auto` and `Never`.The field is `CopilotToolDefer?` (nullable) — absence is expressed as `null`.
697
+
-**Node.js**: `defer?:"auto"|"never"` — absence is expressed as `undefined` (the field is optional).
698
+
-**Go**:Would use a pointer or zero value.
699
+
700
+
Every other SDK uses **nullability/optionality** to represent "no defer preference."The agent invented `NONE("")` to solve a Java annotation limitation: annotation attributes can't be `null`, so a sentinel value is needed for the default.
701
+
702
+
This is a reasonable Java-specific workaround (annotations require compile-time constants), but it introduces a concern: `NONE("")` will serialize as `""` via `@JsonValue` if it's ever accidentally included in a JSON-RPC message. The processor/`fromObject()` code must treat `NONE` as equivalent to `null` (i.e., don't pass it to `ToolDefinition.create()`). You'll want to verify that gate exists in task 4.3/4.4.
703
+
704
+
### 18:45Prompt
705
+
706
+
Let's take .NET. What is the behavior of the tool in the "absence" case? And what does that serialize as?
707
+
708
+
### 18:47 Response
709
+
710
+
711
+
Updated todo list
712
+
713
+
Read [](file:///Users/edburns/workareas/copilot-sdk/dotnet/src/CopilotTool.cs#140-140), lines 140 to 160
714
+
715
+
Read [](file:///Users/edburns/workareas/copilot-sdk/dotnet/src/Client.cs#2415-2415), lines 2415 to 2450
716
+
717
+
Now let me see how `ToolDefinition` serializes when `Defer` is null:
718
+
719
+
Searched for regex `ToolDefinition.*serial|WriteJson|JsonSerializ|toolDefinition.*json|RegisterTools|registerTools` (`**/dotnet/src/Client.cs`), 20 results
720
+
721
+
Read [](file:///Users/edburns/workareas/copilot-sdk/dotnet/src/Client.cs#2117-2117), lines 2117 to 2130
722
+
723
+
There's the answer:
724
+
725
+
**In.NET, when `Defer` is `null`, the key is simply omitted from the JSON.**
726
+
727
+
The serializer uses `DefaultIgnoreCondition=JsonIgnoreCondition.WhenWritingNull`, so any `null`-valued property (like `Defer`, `OverridesBuiltInTool`, `SkipPermission`) is not written to the wire at all. TheCLI receives a `ToolDefinition` JSON object with no `defer` key — meaning "no preference, use server default."
728
+
729
+
So the wire behavior for"absence" is:**the `defer` field does not appear in the JSON-RPC message**.
730
+
731
+
---
732
+
733
+
ForJava's `NONE("")`: if Jackson serializes it, it would emit `"defer": ""` — which is **not the same** as omitting the key. The Java code must treat `NONE` as "do not serialize this field" (i.e., pass `null` to `ToolDefinition.create()` for the defer parameter). The `@JsonValue` of `""` is a landmine if it ever leaks to the wire.
734
+
735
+
### 19:11 Prompt
736
+
737
+
For all the created issues please find the right place to add the following requirement:
738
+
739
+
✅✅ YOU MUST run `mvn spotless:apply` before every commit.
0 commit comments