Skip to content

Commit 6dd2031

Browse files
authored
{tool, examples}: support read_multiple_files tool for file tool set (#361)
Support read_multiple_files tool for file tool set. In the previous debugagent example, we can see that the read_file tool is called multiple times in succession. However, calling tools requires LLM to initiate these calls, which is time-consuming. Therefore, the read_multiple_files tool is provided to read multiple files in a single tool call, improving the debugagent's processing speed. Compared to the previous 10 tool calls, only 5 are now required.
1 parent 90a13ab commit 6dd2031

File tree

11 files changed

+389
-168
lines changed

11 files changed

+389
-168
lines changed

examples/debugagent/README.md

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,9 @@ go run main.go -base-dir ./project
8181
Model: deepseek-chat
8282
Base Directory: ./project
8383
Type 'exit' to end the conversation
84-
Available tools: save_file, read_file, list_file, search_file, search_content, replace_content
84+
Available tools: save_file, read_file, read_multiple_files, list_file, search_file, search_content, replace_content
8585
==================================================
86-
✅ Debug agent ready! Session: debug-session-1757927735
86+
✅ Debug agent ready! Session: debug-session-1758004914
8787
8888
💡 Try asking questions like:
8989
- Save a file called 'hello.txt' with content 'Hello, World!'
@@ -95,111 +95,72 @@ Available tools: save_file, read_file, list_file, search_file, search_content, r
9595
9696
ℹ️ Note: All file operations will be performed in the base directory
9797
98-
👤 You: The current directory is a code project. Can you help me fix the bug?
99-
🤖 Assistant: I'll help you fix the bug in your code project. First, let me explore the project structure to understand what we're working with.
98+
👤 You: 🤖 Assistant: I'd be happy to help you fix the bug! To get started, I need to understand the project structure and the codebase. Let me first explore the current directory to see what kind of project this is.
10099
101100
🔧 Tool call initiated:
102-
• list_file (ID: call_00_HbOP1G2E410C9TKlajhsPY6L)
103-
Arguments: {"path": "."}
101+
• list_file (ID: call_00_NgmwIy6qMBDas1fm0CYPU9PZ)
102+
Arguments: {"path": ""}
104103
🔄 Executing tools...
105-
✅ Tool result (ID: call_00_HbOP1G2E410C9TKlajhsPY6L): {"base_directory":"project","path":".","files":["README.md","expect.txt","go.mod","input.txt","main.go","output.txt"],"folders":["counter"],"message":"Found 6 files and 1 folders in ."}
104+
✅ Tool result (ID: call_00_NgmwIy6qMBDas1fm0CYPU9PZ): {"base_directory":"project","path":"","files":["README.md","expect.txt","go.mod","input.txt","main.go","output.txt"],"folders":["counter"],"message":"Found 6 files and 1 folders in base directory"}
106105
107-
Let me examine the main files to understand the project structure and identify potential bugs:
106+
This appears to be a Go project. Let me examine the main files to understand the structure and identify the bug:
108107
109108
🔧 Tool call initiated:
110-
read_file (ID: call_00_HtevwNGY6sZVY0sGxym3txiJ)
111-
Arguments: {"file_name": "main.go"}
109+
read_multiple_files (ID: call_00_IPpAT8AFnUG3ZmzcKstPJoZ5)
110+
Arguments: {"patterns": ["README.md", "go.mod", "main.go"]}
112111
🔄 Executing tools...
113-
✅ Tool result (ID: call_00_HtevwNGY6sZVY0sGxym3txiJ): {"base_directory":"project","file_name":"main.go","contents":"//\n// Tencent is pleased to support the open source community by making trpc-agent-go available.\n//\n// Copyright (C) 2025 Tencent. All rights reserved.\n//\n// trpc-agent-go is licensed under the Apache License Version 2.0.\n//\n//\n\n// package main is a example project with bug.\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"trpc.group/trpc-go/trpc-agent-go/examples/debugagent/project/counter\"\n)\n\nfunc main() {\n\tcontent, err := os.ReadFile(\"input.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tn, err := strconv.Atoi(strings.TrimSpace(string(content)))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tcounter := counter.GetCounter(n)\n\tos.WriteFile(\"output.txt\", []byte(strconv.Itoa(counter)), 0644)\n}\n","message":"Successfully read main.go, start line: 1, end line: 34, total lines: 34"}
114-
112+
✅ Tool result (ID: call_00_IPpAT8AFnUG3ZmzcKstPJoZ5): {"base_directory":"project","files":[{"file_name":"README.md","contents":"input.txt: Program input\noutput.txt: Program output\nexpect.txt: Program expected output\n\nWe've discovered that the program's actual output doesn't match our expectations. Could you help us debug this?\n","message":"Successfully read README.md, total lines: 6"},{"file_name":"go.mod","contents":"module trpc.group/trpc-go/trpc-agent-go/examples/debugagent/project\n\ngo 1.24.1\n","message":"Successfully read go.mod, total lines: 4"},{"file_name":"main.go","contents":"//\n// Tencent is pleased to support the open source community by making trpc-agent-go available.\n//\n// Copyright (C) 2025 Tencent. All rights reserved.\n//\n// trpc-agent-go is licensed under the Apache License Version 2.0.\n//\n//\n\n// package main is a example project with bug.\npackage main\n\nimport (\n\t\"log\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"trpc.group/trpc-go/trpc-agent-go/examples/debugagent/project/counter\"\n)\n\nfunc main() {\n\tcontent, err := os.ReadFile(\"input.txt\")\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tn, err := strconv.Atoi(strings.TrimSpace(string(content)))\n\tif err != nil {\n\t\tlog.Fatal(err)\n\t}\n\tcounter := counter.GetCounter(n)\n\tos.WriteFile(\"output.txt\", []byte(strconv.Itoa(counter)), 0644)\n}\n","message":"Successfully read main.go, total lines: 34"}],"message":"Read 3 file(s)"}
115113
114+
Now let me check the counter package and the input/output files to understand the issue:
116115
117116
🔧 Tool call initiated:
118-
read_file (ID: call_00_sLkTomOHHTEkh4zHwjMTnTAa)
119-
Arguments: {"file_name": "go.mod"}
117+
read_multiple_files (ID: call_00_07r9jkkklLsKwFQNFF7rc9Yw)
118+
Arguments: {"patterns": ["counter/*.go", "input.txt", "output.txt", "expect.txt"]}
120119
🔄 Executing tools...
121-
✅ Tool result (ID: call_00_sLkTomOHHTEkh4zHwjMTnTAa): {"base_directory":"project","file_name":"go.mod","contents":"module trpc.group/trpc-go/trpc-agent-go/examples/debugagent/project\n\ngo 1.24.1\n","message":"Successfully read go.mod, start line: 1, end line: 4, total lines: 4"}
122-
123-
124-
125-
🔧 Tool call initiated:
126-
• read_file (ID: call_00_81p4bcqdUhV1hKtTuKFUASK8)
127-
Arguments: {"file_name": "counter/counter.go"}
128-
🔄 Executing tools...
129-
✅ Tool result (ID: call_00_81p4bcqdUhV1hKtTuKFUASK8): {"base_directory":"project","file_name":"counter/counter.go","contents":"//\n// Tencent is pleased to support the open source community by making trpc-agent-go available.\n//\n// Copyright (C) 2025 Tencent. All rights reserved.\n//\n// trpc-agent-go is licensed under the Apache License Version 2.0.\n//\n//\n\n// package counter implements a counter.\npackage counter\n\nimport \"sync/atomic\"\n\nfunc GetCounter(n int) int {\n\tvar counter int64\n\tfor i := 0; i \u003c n; i++ {\n\t\tgo func() {\n\t\t\tatomic.AddInt64(\u0026counter, 1)\n\t\t}()\n\t}\n\treturn int(counter)\n}\n","message":"Successfully read counter/counter.go, start line: 1, end line: 24, total lines: 24"}
130-
131-
132-
133-
🔧 Tool call initiated:
134-
• read_file (ID: call_00_vHV6YCLhCW70BW7YuU10ykGx)
135-
Arguments: {"file_name": "input.txt"}
136-
🔄 Executing tools...
137-
✅ Tool result (ID: call_00_vHV6YCLhCW70BW7YuU10ykGx): {"base_directory":"project","file_name":"input.txt","contents":"100000","message":"Successfully read input.txt, start line: 1, end line: 1, total lines: 1"}
138-
139-
120+
✅ Tool result (ID: call_00_07r9jkkklLsKwFQNFF7rc9Yw): {"base_directory":"project","files":[{"file_name":"counter/counter.go","contents":"//\n// Tencent is pleased to support the open source community by making trpc-agent-go available.\n//\n// Copyright (C) 2025 Tencent. All rights reserved.\n//\n// trpc-agent-go is licensed under the Apache License Version 2.0.\n//\n//\n\n// package counter implements a counter.\npackage counter\n\nimport \"sync/atomic\"\n\nfunc GetCounter(n int) int {\n\tvar counter int64\n\tfor i := 0; i \u003c n; i++ {\n\t\tgo func() {\n\t\t\tatomic.AddInt64(\u0026counter, 1)\n\t\t}()\n\t}\n\treturn int(counter)\n}\n","message":"Successfully read counter/counter.go, total lines: 24"},{"file_name":"expect.txt","contents":"100000","message":"Successfully read expect.txt, total lines: 1"},{"file_name":"input.txt","contents":"100000","message":"Successfully read input.txt, total lines: 1"},{"file_name":"output.txt","contents":"97876","message":"Successfully read output.txt, total lines: 1"}],"message":"Read 4 file(s)"}
140121
141-
🔧 Tool call initiated:
142-
• read_file (ID: call_00_WfDPQn8WomiYbRHTgCq0y3nI)
143-
Arguments: {"file_name": "expect.txt"}
144-
🔄 Executing tools...
145-
✅ Tool result (ID: call_00_WfDPQn8WomiYbRHTgCq0y3nI): {"base_directory":"project","file_name":"expect.txt","contents":"100000","message":"Successfully read expect.txt, start line: 1, end line: 1, total lines: 1"}
146-
147-
148-
149-
🔧 Tool call initiated:
150-
• read_file (ID: call_00_1VC04qSLOUSKYBVGvkAWJX2J)
151-
Arguments: {"file_name": "output.txt"}
152-
🔄 Executing tools...
153-
✅ Tool result (ID: call_00_1VC04qSLOUSKYBVGvkAWJX2J): {"base_directory":"project","file_name":"output.txt","contents":"97876","message":"Successfully read output.txt, start line: 1, end line: 1, total lines: 1"}
154-
155-
Now I can see the bug! The issue is in the `counter/counter.go` file. The problem is that the main function returns immediately after spawning goroutines, without waiting for them to complete. The goroutines are still running when the function returns, so the counter value is not fully incremented.
156-
157-
Let me also check if there's a README that might provide more context:
158-
159-
🔧 Tool call initiated:
160-
• read_file (ID: call_00_E8Os7PrurC09MQHPGcdy7X72)
161-
Arguments: {"file_name": "README.md"}
162-
🔄 Executing tools...
163-
✅ Tool result (ID: call_00_E8Os7PrurC09MQHPGcdy7X72): {"base_directory":"project","file_name":"README.md","contents":"input.txt: Program input\noutput.txt: Program output\nexpect.txt: Program expected output\n\nWe've discovered that the program's actual output doesn't match our expectations. Could you help us debug this?\n","message":"Successfully read README.md, start line: 1, end line: 6, total lines: 6"}
122+
Now I can see the issue! The problem is in the `counter/counter.go` file. The program is spawning multiple goroutines to increment a counter using `atomic.AddInt64`, but it's not waiting for all goroutines to complete before returning the result.
164123
165-
Perfect! The issue is clear now. The program reads 100000 from input.txt, spawns 100000 goroutines to increment a counter, but returns before all goroutines finish executing. This is why the output (97876) is less than the expected value (100000).
124+
The bug is that the `GetCounter` function returns immediately after starting all the goroutines, without waiting for them to finish. This means the counter value returned is incomplete - some goroutines haven't had time to execute yet.
166125
167-
The fix is to add synchronization to wait for all goroutines to complete before returning. I'll use a `sync.WaitGroup` to fix this:
126+
Let me fix this by adding proper synchronization using a WaitGroup:
168127
169128
🔧 Tool call initiated:
170-
• replace_content (ID: call_00_EVnrOAunnIK53rENeMoRsbQ2)
129+
• replace_content (ID: call_00_i62KTD9uzX0enr32vjsGKkrW)
171130
Arguments: {"file_name": "counter/counter.go", "old_string": "import \"sync/atomic\"\n\nfunc GetCounter(n int) int {\n\tvar counter int64\n\tfor i := 0; i < n; i++ {\n\t\tgo func() {\n\t\t\tatomic.AddInt64(&counter, 1)\n\t\t}()\n\t}\n\treturn int(counter)\n}", "new_string": "import (\n\t\"sync\"\n\t\"sync/atomic\"\n)\n\nfunc GetCounter(n int) int {\n\tvar counter int64\n\tvar wg sync.WaitGroup\n\t\n\tfor i := 0; i < n; i++ {\n\t\twg.Add(1)\n\t\tgo func() {\n\t\t\tdefer wg.Done()\n\t\t\tatomic.AddInt64(&counter, 1)\n\t\t}()\n\t}\n\t\n\twg.Wait()\n\treturn int(counter)\n}"}
172131
🔄 Executing tools...
173-
✅ Tool result (ID: call_00_EVnrOAunnIK53rENeMoRsbQ2): {"base_directory":"project","file_name":"counter/counter.go","message":"Successfully replaced 1 of 1 occurrence(s) in 'counter/counter.go'"}
132+
✅ Tool result (ID: call_00_i62KTD9uzX0enr32vjsGKkrW): {"base_directory":"project","file_name":"counter/counter.go","message":"Successfully replaced 1 of 1 occurrence(s) in 'counter/counter.go'"}
174133
175-
Now let's test the fix by running the program:
134+
Now let me run the program to test the fix:
176135
177136
🔧 Tool call initiated:
178-
• save_file (ID: call_00_GvwRuY58gI6EWVXfQUcAlOg3)
179-
Arguments: {"file_name": "run.sh", "contents": "#!/bin/bash\n# Clean up previous output\nrm -f output.txt\n\n# Run the program\ngo run .\n\n# Check the result\necho \"Expected: $(cat expect.txt)\"\necho \"Actual: $(cat output.txt)\"\n\n# Compare with expected output\nif [ \"$(cat expect.txt)\" = \"$(cat output.txt)\" ]; then\n echo \"\u2705 Test PASSED - Output matches expected value\"\nelse\n echo \"\u274c Test FAILED - Output does not match expected value\"\n exit 1\nfi", "overwrite": true}
137+
• save_file (ID: call_00_utm8PWsrTczD4BNZYQzT9RmJ)
138+
Arguments: {"file_name": "run.sh", "contents": "#!/bin/bash\n# Run the Go program\ngo run .\n# Compare output with expected result\necho \"Expected: $(cat expect.txt)\"\necho \"Actual: $(cat output.txt)\"\nif diff -q output.txt expect.txt > /dev/null; then\n echo \"\u2705 Test passed! Output matches expected result.\"\nelse\n echo \"\u274c Test failed! Output does not match expected result.\"\n diff output.txt expect.txt\nfi", "overwrite": true}
180139
🔄 Executing tools...
181-
✅ Tool result (ID: call_00_GvwRuY58gI6EWVXfQUcAlOg3): {"base_directory":"project","file_name":"run.sh","message":"Successfully saved: run.sh"}
140+
✅ Tool result (ID: call_00_utm8PWsrTczD4BNZYQzT9RmJ): {"base_directory":"project","file_name":"run.sh","message":"Successfully saved: run.sh"}
182141
183142
```bash
184143
bash ./run.sh
185144
```
186-
✅ Code execution: ```bash
145+
✅ Code execution:
146+
```bash
187147
bash ./run.sh
188148
```
189149
190150
191-
✅ Code execution: Code execution result:
151+
✅ Code execution:
152+
Code execution result:
192153
Expected: 100000
193154
Actual: 100000
194-
✅ Test PASSED - Output matches expected value
155+
✅ Test passed! Output matches expected result.
195156
``````
196157

197158
## How It Works
198159

199160
1. **Setup**: Creates an LLM agent with file tools and a local CodeExecutor.
200161
2. **User Input**: You ask for debugging help or file tasks under `-base-dir`.
201162
3. **Tool/Execution Decision**: The agent decides to use file tools or execute code:
202-
- File tools: `read_file`, `list_file`, `search_file`, `search_content`, `replace_content`, `save_file`.
163+
- File tools: `read_file`, `list_file`, `search_file`, `search_content`, `replace_content`, `save_file`, `read_multiple_files`.
203164
- Code execution: emit a single fenced `bash` block, or write a script then immediately run it.
204165
4. **File Operation Execution** (when applicable): File tools run and return structured results.
205166
5. **Code Execution** (when applicable): The CodeExecution processor extracts the fenced block and runs it in the working dir, then emits two post‑processing events — one with the code, one with the result. The UI prints the result cleanly without duplicating the code block.

examples/debugagent/main.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func main() {
4040
fmt.Printf("Model: %s\n", *modelName)
4141
fmt.Printf("Base Directory: %s\n", *baseDir)
4242
fmt.Printf("Type 'exit' to end the conversation\n")
43-
fmt.Printf("Available tools: save_file, read_file, list_file, search_file, search_content, replace_content\n")
43+
fmt.Printf("Available tools: save_file, read_file, read_multiple_files, list_file, search_file, search_content, replace_content\n")
4444
fmt.Println(strings.Repeat("=", 50))
4545
// Create and run the chat.
4646
chat := &debugChat{
@@ -116,14 +116,16 @@ func (c *debugChat) setup(ctx context.Context) error {
116116
"",
117117
"File Operation Rules:",
118118
"- read_file, list_files, search_files, search_content: can run without confirmation.",
119-
"- read_many_files: Prefer this to read multiple files in a single call to reduce round-trips.",
119+
"- read_multiple_files: Prefer this when you need multiple files in one call to reduce round-trips.",
120+
" Use read_file when you need partial ranges of a single file (start_line/num_lines).",
120121
"- save_file, replace_content: MUST ask for user confirmation before overwriting/creating files.",
121122
"- Prefer replace_content over save_file for small edits; be precise and explain planned changes.",
122123
"",
123124
"Available Tools:",
124125
"- save_file: Save content to files (confirmation required).",
125126
"- replace_content: Replace specific strings (confirmation required). Prefer this for small edits.",
126127
"- read_file: Read file contents.",
128+
"- read_multiple_files: Read multiple files in a single call.",
127129
"- list_files: List files and directories.",
128130
"- search_files: Search for files by pattern.",
129131
"- search_content: Search for content by pattern.",

examples/go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ require (
2727
)
2828

2929
require (
30-
github.com/bmatcuk/doublestar/v4 v4.6.1 // indirect
30+
github.com/bmatcuk/doublestar/v4 v4.9.1 // indirect
3131
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
3232
github.com/cespare/xxhash/v2 v2.3.0 // indirect
3333
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
@@ -42,6 +42,8 @@ require (
4242
github.com/google/uuid v1.6.0 // indirect
4343
github.com/gorilla/mux v1.8.1 // indirect
4444
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
45+
github.com/hashicorp/errwrap v1.0.0 // indirect
46+
github.com/hashicorp/go-multierror v1.1.1 // indirect
4547
github.com/invopop/yaml v0.2.0 // indirect
4648
github.com/josharian/intern v1.0.0 // indirect
4749
github.com/lestrrat-go/blackmagic v1.0.2 // indirect

examples/go.sum

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
github.com/alicebob/miniredis/v2 v2.35.0 h1:QwLphYqCEAo1eu1TqPRN2jgVMPBweeQcR21jeqDCONI=
22
github.com/alicebob/miniredis/v2 v2.35.0/go.mod h1:TcL7YfarKPGDAthEtl5NBeHZfeUQj6OXMm/+iu5cLMM=
3-
github.com/bmatcuk/doublestar/v4 v4.6.1 h1:FH9SifrbvJhnlQpztAx++wlkk70QBf0iBWDwNy7PA4I=
4-
github.com/bmatcuk/doublestar/v4 v4.6.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
3+
github.com/bmatcuk/doublestar/v4 v4.9.1 h1:X8jg9rRZmJd4yRy7ZeNDRnM+T3ZfHv15JiBJ/avrEXE=
4+
github.com/bmatcuk/doublestar/v4 v4.9.1/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
55
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
66
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
77
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
@@ -42,6 +42,10 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
4242
github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
4343
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys=
4444
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I=
45+
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
46+
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
47+
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
48+
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
4549
github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
4650
github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
4751
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=

go.mod

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@ module trpc.group/trpc-go/trpc-agent-go
33
go 1.21
44

55
require (
6-
github.com/bmatcuk/doublestar/v4 v4.6.1
6+
github.com/bmatcuk/doublestar/v4 v4.9.1
77
github.com/gomutex/godocx v0.1.5
88
github.com/gonfva/docxlib v0.0.0-20210517191039-d8f39cecf1ad
99
github.com/google/go-cmp v0.6.0
1010
github.com/google/uuid v1.6.0
1111
github.com/gorilla/mux v1.8.1
12+
github.com/hashicorp/go-multierror v1.1.1
1213
github.com/mattn/go-sqlite3 v1.14.32
1314
github.com/openai/openai-go v1.12.0
1415
github.com/panjf2000/ants/v2 v2.9.0
@@ -50,6 +51,7 @@ require (
5051
github.com/golang/glog v1.2.1 // indirect
5152
github.com/google/go-querystring v1.0.0 // indirect
5253
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
54+
github.com/hashicorp/errwrap v1.0.0 // indirect
5355
github.com/invopop/yaml v0.2.0 // indirect
5456
github.com/josharian/intern v1.0.0 // indirect
5557
github.com/lestrrat-go/blackmagic v1.0.2 // indirect

0 commit comments

Comments
 (0)