Skip to content

Commit 7170c52

Browse files
Jakub ZikaJakub Zika
authored andcommitted
Fix hanging LSP diagnostics requests with configurable timeout
Prevents ECA from hanging indefinitely when editor diagnostic requests don't respond by adding a configurable timeout mechanism.
1 parent 18c15fa commit 7170c52

File tree

5 files changed

+37
-26
lines changed

5 files changed

+37
-26
lines changed

CHANGELOG.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
## Unreleased
44

55
- Fix reasoning titles in thoughts blocks for openai-responses.
6+
- Fix hanging LSP diagnostics requests
7+
- Add `lspTimeoutSeconds` to config
68

79
## 0.32.4
810

@@ -22,7 +24,7 @@
2224

2325
## 0.32.0
2426

25-
- Refactor config for better UX and understanding:
27+
- Refactor config for better UX and understanding:
2628
- Move `models` to inside `providers`.
2729
- Make `customProviders` compatible with `providers`. models need to be a map now, not a list.
2830

@@ -32,7 +34,7 @@
3234
- Drop uneeded `ollama useTools` and `ollama think` configs.
3335
- Refactor configs for config providers unification.
3436
- `<provider>ApiKey` and `<providerApiUrl>` now live in `:providers "<provider>" :key`.
35-
- Move `defaultModel` config from customProvider to root.
37+
- Move `defaultModel` config from customProvider to root.
3638

3739
## 0.30.0
3840

docs/configuration.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ There are multiples ways to configure ECA:
1818
}
1919
}
2020
```
21-
21+
2222
=== "Local Config file"
2323

2424
Convenient for users
@@ -31,7 +31,7 @@ There are multiples ways to configure ECA:
3131
}
3232
}
3333
```
34-
34+
3535
=== "InitializationOptions"
3636

3737
Convenient for editors
@@ -124,7 +124,7 @@ There are 3 possible ways to configure rules following this order of priority:
124124

125125
`.eca/rules/talk_funny.md`
126126
```markdown
127-
---
127+
---
128128
description: Use when responding anything
129129
---
130130

@@ -137,7 +137,7 @@ There are 3 possible ways to configure rules following this order of priority:
137137

138138
`~/.config/eca/rules/talk_funny.md`
139139
```markdown
140-
---
140+
---
141141
description: Use when responding anything
142142
---
143143

@@ -186,6 +186,7 @@ There are 3 possible ways to configure rules following this order of priority:
186186
manualApproval?: boolean | string[], // manual approve all tools or the specified tools
187187
};
188188
mcpTimeoutSeconds: number;
189+
lspTimeoutSeconds: number;
189190
mcpServers: {[key: string]: {
190191
command: string;
191192
args?: string[];
@@ -232,6 +233,7 @@ There are 3 possible ways to configure rules following this order of priority:
232233
"manualApproval": null,
233234
},
234235
"mcpTimeoutSeconds" : 60,
236+
"lspTimeoutSeconds" : 30,
235237
"mcpServers" : {},
236238
"chat" : {
237239
"defaultBehavior": "agent"

src/eca/config.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
:editor {:enabled true}}
5757
:disabledTools []
5858
:mcpTimeoutSeconds 60
59+
:lspTimeoutSeconds 30
5960
:mcpServers {}
6061
:chat {:defaultBehavior "agent"
6162
:welcomeMessage "Welcome to ECA!\n\nType '/' for commands\n\n"}

src/eca/features/tools/editor.clj

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,36 @@
77
[eca.messenger :as messenger]
88
[eca.shared :as shared]))
99

10-
(defn ^:private diagnostics [arguments {:keys [messenger]}]
10+
(defn ^:private diagnostics [arguments {:keys [messenger config]}]
1111
(or (tools.util/invalid-arguments arguments [["path" #(or (nil? %)
1212
(string/blank? %)
1313
(not (fs/directory? %))) "Path needs to be a file, not a directory."]])
14-
(let [uri (some-> (get arguments "path") not-empty shared/filename->uri)]
14+
(let [uri (some-> (get arguments "path") not-empty shared/filename->uri)
15+
timeout-ms (* 1000 (get config :lspTimeoutSeconds 30))]
1516
(try
16-
(let [diags (:diagnostics @(messenger/editor-diagnostics messenger uri))]
17-
(if (seq diags)
18-
{:error false
17+
(let [response (deref (messenger/editor-diagnostics messenger uri) timeout-ms ::timeout)]
18+
(if (= response ::timeout)
19+
{:error true
1920
:contents [{:type :text
20-
:text (reduce
21-
(fn [s {:keys [uri range severity code message]}]
22-
(str s (format "%s:%s:%s: %s: %s%s"
23-
(shared/uri->filename uri)
24-
(-> range :start :line)
25-
(-> range :start :character)
26-
severity
27-
(if code (format "[%s] " code) "")
28-
message)))
29-
""
30-
diags)}]}
31-
{:error false
32-
:contents [{:type :text
33-
:text "No diagnostics found"}]}))
21+
:text "Timeout waiting for editor diagnostics response"}]}
22+
(let [diags (:diagnostics response)]
23+
(if (seq diags)
24+
{:error false
25+
:contents [{:type :text
26+
:text (reduce
27+
(fn [s {:keys [uri range severity code message]}]
28+
(str s (format "%s:%s:%s: %s: %s%s"
29+
(shared/uri->filename uri)
30+
(-> range :start :line)
31+
(-> range :start :character)
32+
severity
33+
(if code (format "[%s] " code) "")
34+
message)))
35+
""
36+
diags)}]}
37+
{:error false
38+
:contents [{:type :text
39+
:text "No diagnostics found"}]}))))
3440
(catch Exception e
3541
(logger/error (format "Error getting editor diagnostics for arguments %s: %s" arguments e))
3642
{:error true

test/eca/test_helper.clj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
(chat-content-received [_ data] (swap! messages* update :chat-content-received (fnil conj []) data))
2727
(tool-server-updated [_ data] (swap! messages* update :tool-server-update (fnil conj []) data))
2828
(showMessage [_ data] (swap! messages* update :show-message (fnil conj []) data))
29-
(editor-diagnostics [_ _uri] (delay {:diagnostics @diagnostics*})))
29+
(editor-diagnostics [_ _uri] (future {:diagnostics @diagnostics*})))
3030

3131
(defn ^:private make-components []
3232
{:db* (atom db/initial-db)

0 commit comments

Comments
 (0)