|
| 1 | +## Goal |
| 2 | + |
| 3 | +Port the Java integration test behavior from: |
| 4 | + |
| 5 | +- `java/src/test/java/com/github/copilot/LowLevelToolDefinitionIT.java` |
| 6 | +- test method: `lowLevelToolDefinition` |
| 7 | +- snapshot: `test/snapshots/tools/low_level_tool_definition.yaml` |
| 8 | + |
| 9 | +to the following non-Java SDKs, using each language's native E2E test infrastructure: |
| 10 | + |
| 11 | +1. `dotnet` |
| 12 | +2. `go` |
| 13 | +3. `nodejs` |
| 14 | +4. `python` |
| 15 | +5. `rust` |
| 16 | + |
| 17 | +The new/updated tests in each language must use the **same snapshot scenario** (`tools/low_level_tool_definition`) and validate the same behavior. |
| 18 | + |
| 19 | +--- |
| 20 | + |
| 21 | +## Required test behavior to port |
| 22 | + |
| 23 | +From a test perspective, replicate this behavior: |
| 24 | + |
| 25 | +1. Define a `set_current_phase` tool that accepts a `phase` argument (string, enum: `["searching", "analyzing", "done"]`) and returns `"Phase set to {phase}"`. The tool handler must also store the phase value in test-local state. |
| 26 | +2. Define a `search_items` tool that accepts a `keyword` argument (string) and returns `"Found: item_alpha, item_beta"`. |
| 27 | +3. Define a `grep` override tool (using whatever "override" mechanism the language provides) that accepts a `query` argument (string) and returns `"CUSTOM_GREP: {query}"`. |
| 28 | +4. Create a session with: |
| 29 | + - Permission handler that auto-approves all requests. |
| 30 | + - Available tools: all custom tools (`*`) plus built-in `web_fetch`. |
| 31 | + - The three tool definitions registered on the session. |
| 32 | +5. Send prompt: `"First, set the current phase to 'analyzing'. Then search for items with keyword 'copilot'. Report the phase and search results."` |
| 33 | +6. Assert: |
| 34 | + - The assistant response is non-null/non-empty. |
| 35 | + - The response content (case-insensitive) contains `"analyzing"`. |
| 36 | + - The response content contains `"item_alpha"` or `"item_beta"`. |
| 37 | + - The test-local phase state equals `"analyzing"` (verifying the tool handler was actually invoked). |
| 38 | + |
| 39 | +Do not weaken these assertions. |
| 40 | + |
| 41 | +--- |
| 42 | + |
| 43 | +## Critical execution constraint (must follow exactly) |
| 44 | + |
| 45 | +Proceed through languages **one-at-a-time** in this exact order: |
| 46 | + |
| 47 | +1. `dotnet` |
| 48 | +2. `go` |
| 49 | +3. `nodejs` |
| 50 | +4. `python` |
| 51 | +5. `rust` |
| 52 | + |
| 53 | +❌❌ **Do not continue to the next language unless and until the current language gets a clean run with the new test in isolation.** ❌❌ |
| 54 | + |
| 55 | +Do **not** run full cross-language or full-repo test suites. Let CI/CD handle broad runs. |
| 56 | + |
| 57 | +--- |
| 58 | + |
| 59 | +## Snapshot/name mapping requirements |
| 60 | + |
| 61 | +Ensure each language's test naming/harness maps to: |
| 62 | + |
| 63 | +- snapshot folder: `tools` |
| 64 | +- snapshot file: `low_level_tool_definition.yaml` |
| 65 | + |
| 66 | +Do not create alternate snapshot names for this scenario. |
| 67 | + |
| 68 | +--- |
| 69 | + |
| 70 | +## Per-language isolated run commands |
| 71 | + |
| 72 | +Use these commands for isolated validation while iterating. |
| 73 | + |
| 74 | +### 1) dotnet |
| 75 | + |
| 76 | +Implement in dotnet E2E tests (preferred: new `LowLevelToolDefinitionE2ETests` class or add to existing `ToolsE2ETests` class using snapshot category `tools`, test method `Low_Level_Tool_Definition`). |
| 77 | + |
| 78 | +Isolated run: |
| 79 | + |
| 80 | +```bash |
| 81 | +cd dotnet && dotnet test test/GitHub.Copilot.SDK.Test.csproj --filter "FullyQualifiedName~Low_Level_Tool_Definition" |
| 82 | +``` |
| 83 | + |
| 84 | +### 2) go |
| 85 | + |
| 86 | +Implement in Go E2E tests with snapshot mapping to `tools/low_level_tool_definition` (preferred: add to existing `go/internal/e2e/tools_e2e_test.go` or create new file, subtest name exactly `low_level_tool_definition`). |
| 87 | + |
| 88 | +Isolated run: |
| 89 | + |
| 90 | +```bash |
| 91 | +cd go && go test ./internal/e2e -run 'TestToolsE2E/low_level_tool_definition$' -count=1 |
| 92 | +``` |
| 93 | + |
| 94 | +### 3) nodejs |
| 95 | + |
| 96 | +Implement in Node E2E Vitest (preferred: add to existing `nodejs/test/e2e/tools.e2e.test.ts` or create new file, test name mapping to `low_level_tool_definition`). |
| 97 | + |
| 98 | +Isolated run: |
| 99 | + |
| 100 | +```bash |
| 101 | +cd nodejs && npm test -- test/e2e/tools.e2e.test.ts -t "low_level_tool_definition" |
| 102 | +``` |
| 103 | + |
| 104 | +### 4) python |
| 105 | + |
| 106 | +Implement in Python E2E pytest (preferred: add to existing `python/e2e/test_tools_e2e.py` or create new file, test function `test_low_level_tool_definition`). |
| 107 | + |
| 108 | +Isolated run: |
| 109 | + |
| 110 | +```bash |
| 111 | +cd python && uv run pytest e2e/test_tools_e2e.py::test_low_level_tool_definition |
| 112 | +``` |
| 113 | + |
| 114 | +### 5) rust |
| 115 | + |
| 116 | +Implement in Rust E2E tests (preferred: add to existing `rust/tests/e2e/tools.rs`; use `with_e2e_context("tools", "low_level_tool_definition", ...)`). |
| 117 | + |
| 118 | +Isolated run: |
| 119 | + |
| 120 | +```bash |
| 121 | +cd rust && cargo test --features test-support --test e2e tools::low_level_tool_definition -- --exact |
| 122 | +``` |
| 123 | + |
| 124 | +--- |
| 125 | + |
| 126 | +## Implementation notes |
| 127 | + |
| 128 | +1. Reuse existing per-language E2E harness helpers and style conventions. |
| 129 | +2. Keep changes scoped to test code and required wiring. |
| 130 | +3. Do not hand-edit generated code. |
| 131 | +4. ❌❌❌ DO NOT CHANGE ANY non-test CODE.❌❌❌ |
| 132 | +5. ✅✅Put the test in the "right place" for each language. That means put it "near" any similar existing tests. The existing tools E2E test files are: |
| 133 | + - `dotnet/test/E2E/ToolsE2ETests.cs` |
| 134 | + - `go/internal/e2e/tools_e2e_test.go` |
| 135 | + - `nodejs/test/e2e/tools.e2e.test.ts` |
| 136 | + - `python/e2e/test_tools_e2e.py` |
| 137 | + - `rust/tests/e2e/tools.rs` |
| 138 | + Put the new test near those. ✅✅ |
| 139 | +6. The snapshot `test/snapshots/tools/low_level_tool_definition.yaml` involves **two conversations**: one where tool calls are made without prior tool results, and one full round-trip (tool calls → tool results → final assistant message). Each language's replay proxy handles this; just ensure the test sends the right prompt and processes tool invocations correctly. |
| 140 | +7. The `grep` override tool uses whatever "tool override" mechanism exists in each language (e.g., `ToolDefinition.createOverride` in Java, or the equivalent in each SDK). If a language has no override concept, define it as a regular custom tool named `grep`. |
| 141 | + |
| 142 | +--- |
| 143 | + |
| 144 | +## Deliverable |
| 145 | + |
| 146 | +When done, provide: |
| 147 | + |
| 148 | +1. files changed per language, |
| 149 | +2. isolated command used per language, |
| 150 | +3. pass/fail result per language (must be passing before moving to next), |
| 151 | +4. any blockers (if any language cannot be completed). |
0 commit comments