Skip to content

Commit 80397bb

Browse files
committed
Merge branch 'completion'
2 parents d5e2e12 + cd59656 commit 80397bb

File tree

22 files changed

+772
-493
lines changed

22 files changed

+772
-493
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
- Add `:config-file` cli option to pass in config.
6+
- Add support for completion. #12
67

78
## 0.72.2
89

docs/configuration.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,10 @@ To configure, add your OTLP collector config via `:otlp` map following [otlp aut
495495
maxEntriesPerDir?: number;
496496
};
497497
};
498+
completion?: {
499+
model?: string;
500+
systemPromptFile?: string;
501+
};
498502
otlp?: {[key: string]: string};
499503
}
500504
```
@@ -562,6 +566,10 @@ To configure, add your OTLP collector config via `:otlp` map following [otlp aut
562566
"maxTotalEntries": 800,
563567
"maxEntriesPerDir": 50
564568
}
569+
},
570+
"completion": {
571+
"model": "openai/gpt-4o",
572+
"systemPromptFile": "prompts/inline_completion.md"
565573
}
566574
}
567575
```

docs/protocol.md

Lines changed: 85 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,30 @@ The protocol defines a set of lifecycle messages that manage the connection and
8787
Note right of S: Server stops its process
8888
```
8989

90+
### Basic structures
91+
92+
```typescript
93+
export type ErrorType = 'error' | 'warning' | 'info';
94+
95+
interface Error {
96+
type: ErrorType;
97+
message: string;
98+
}
99+
100+
interface Range {
101+
start: {
102+
line: number;
103+
character: number;
104+
};
105+
106+
end: {
107+
line: number;
108+
character: number;
109+
};
110+
}
111+
```
112+
113+
90114
### Initialize (↩️)
91115

92116
The first request sent from client to server. This message:
@@ -1274,17 +1298,7 @@ interface EditorDiagnostic {
12741298
/**
12751299
* The diagnostic range (1-based).
12761300
*/
1277-
range: {
1278-
start: {
1279-
line: number;
1280-
character: number;
1281-
};
1282-
1283-
end: {
1284-
line: number;
1285-
character: number;
1286-
};
1287-
};
1301+
range: Range;
12881302

12891303
/**
12901304
* The diagnostic code. Ex: 'wrong-args'
@@ -1300,7 +1314,65 @@ interface EditorDiagnostic {
13001314

13011315
### Completion (↩️)
13021316

1303-
Soon
1317+
A request sent from client to server, asking for a text to be presented to user as a inline completion for the current text code.
1318+
1319+
_Request:_
1320+
1321+
* method: `completion/inline`
1322+
* params: `CompletionInlineParams` defined as follows:
1323+
1324+
```typescript
1325+
interface CompletionInlineParams {
1326+
/**
1327+
* The current document text.
1328+
*/
1329+
docText: string;
1330+
1331+
/**
1332+
* The document version.
1333+
* Clients should increment this on their side each time document is changed.
1334+
* Server will return this on its completion so clients can
1335+
* discard if document was changed/version was increased.
1336+
*/
1337+
docVersion: number;
1338+
1339+
/**
1340+
* The cursor position.
1341+
*/
1342+
position: {
1343+
line: number;
1344+
character: number;
1345+
};
1346+
}
1347+
```
1348+
1349+
_Response:_ `CompletionInlineResponse | Error`
1350+
1351+
```typescript
1352+
interface CompletionInlineResponse {
1353+
/**
1354+
* The items available as completion.
1355+
*/
1356+
items: CompletionInlineItem[];
1357+
}
1358+
1359+
interface CompletionInlineItem {
1360+
/**
1361+
* The item text
1362+
*/
1363+
text: string;
1364+
1365+
/**
1366+
* The item doc-version
1367+
*/
1368+
docVersion: number;
1369+
1370+
/**
1371+
* The range of this new text in the document
1372+
*/
1373+
range: Range;
1374+
}
1375+
```
13041376

13051377
### Edit (↩️)
13061378

@@ -1494,17 +1566,5 @@ _Request:_
14941566
* params: `ShowMessageParams` defined as follows:
14951567

14961568
```typescript
1497-
interface ShowMessageParams {
1498-
/**
1499-
* The message type. See {@link MessageType}.
1500-
*/
1501-
type: MessageType;
1502-
1503-
/**
1504-
* The actual message.
1505-
*/
1506-
message: string;
1507-
}
1508-
1509-
export type MessageType = 'error' | 'warning' | 'info';
1569+
type ShowMessageParams = Error;
15101570
```

integration-test/llm_mock/anthropic.clj

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -206,19 +206,10 @@
206206
(hk/close ch)))))
207207

208208
(defn ^:private chat-title-text-0 [ch]
209-
(sse-send! ch "content_block_delta"
210-
{:type "content_block_delta"
211-
:index 0
212-
:delta {:type "text_delta" :text "Some Cool"}})
213-
(sse-send! ch "content_block_delta"
214-
{:type "content_block_delta"
215-
:index 0
216-
:delta {:type "text_delta" :text " Title"}})
217-
(sse-send! ch "message_delta"
218-
{:type "message_delta"
219-
:delta {:stop_reason "end_turn"}
220-
:usage {:input_tokens 5
221-
:output_tokens 10}})
209+
(hk/send! ch
210+
(json/generate-string
211+
{:content [{:text "Some Cool Title"}]})
212+
true)
222213
(hk/close ch))
223214

224215
(defn handle-anthropic-messages [req]

integration-test/llm_mock/ollama.clj

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,10 @@
6363
(hk/close ch)))))
6464

6565
(defn ^:private chat-title-text-0 [ch]
66-
(sse-send! ch {:message {:thinking "Some Cool"}})
67-
(sse-send! ch {:message {:thinking " Title"}})
68-
(sse-send! ch {:done_reason "stop"})
69-
(hk/close ch))
66+
(hk/send! ch
67+
(json/generate-string
68+
{:message {:content "Some Cool Title"}})
69+
true))
7070

7171
(defn handle-ollama-chat [req]
7272
(let [body-str (slurp (:body req))

integration-test/llm_mock/openai.clj

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,10 @@
180180
(hk/close ch)))))
181181

182182
(defn ^:private chat-title-text-0 [ch]
183-
(sse-send! ch "response.output_text.delta"
184-
{:type "response.output_text.delta" :delta "Some Cool"})
185-
(sse-send! ch "response.output_text.delta"
186-
{:type "response.output_text.delta" :delta " Title"})
187-
(sse-send! ch "response.completed"
188-
{:type "response.completed"
189-
:response {:output []
190-
:usage {:input_tokens 5
191-
:output_tokens 10}
192-
:status "completed"}})
193-
(hk/close ch))
183+
(hk/send! ch
184+
(json/generate-string
185+
{:output [{:content [{:text "Some Cool Title"}]}]})
186+
true))
194187

195188
(defn handle-openai-responses [req]
196189
(let [body (some-> (slurp (:body req))

integration-test/llm_mock/openai_chat.clj

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,10 @@
9090
(hk/close ch))
9191

9292
(defn ^:private chat-title-text-0 [ch]
93-
(send-sse! ch {:choices [{:delta {:content "Some Cool"}}]})
94-
(send-sse! ch {:choices [{:delta {:content " Title"}}]})
95-
(send-sse! ch {:usage {:prompt_tokens 5 :completion_tokens 10}})
96-
(send-sse! ch {:choices [{:delta {} :finish_reason "stop"}]})
97-
(hk/close ch))
93+
(hk/send! ch
94+
(json/generate-string
95+
{:choices [{:message {:content "Some Cool Title"}}]})
96+
true))
9897

9998
(defn handle-openai-chat [req]
10099
;; Capture and normalize the request body for assertions in tests
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
You are ECA Code Completer, an editor-native code completion engine.
2+
3+
## Objective
4+
5+
Given user code with <ECA_TAG>, generate the correct and useful text that the developer would likely write replacing that tag. Output only the text that directly replaces the ECA tag.
6+
7+
## Core rules
8+
9+
- Keep completions concise and safe: prefer 1–5 lines that compile, end at a natural boundary, and do not over-start or over-close scopes.
10+
- Match file style exactly: respect indentation, naming conventions, import/usings syntax, quotes, semicolons, docstring format, and line wrapping.
11+
- Favor in-scope symbols over inventing new ones; use existing helpers, types, and constants whenever possible.
12+
- If unsure, prefer a short, syntactically valid snippet to a longer guess.
13+
- Infer language from context and fully adhere to its language and framework conventions.
14+
- Never output placeholders or boilerplate such as TODO, FIXME, or lorem ipsum.
15+
- Pay attention on spaces after adding newlines to match the resulting code indentation.

src/eca/config.clj

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,10 @@
118118
:compactPromptFile "prompts/compact.md"
119119
:index {:ignoreFiles [{:type :gitignore}]
120120
:repoMap {:maxTotalEntries 800
121-
:maxEntriesPerDir 50}}})
121+
:maxEntriesPerDir 50}}
122+
:completion {:model "openai/gpt-4o"
123+
:systemPromptFile "prompts/inline_completion.md"}})
124+
122125

123126
(def ^:private fallback-behavior "agent")
124127

src/eca/features/chat.clj

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -561,27 +561,28 @@
561561

562562
(when-not (get-in db [:chats chat-id :title])
563563
(future
564-
(when-let [title @(llm-api/simple-prompt
565-
{:provider provider
566-
:model model
567-
:model-capabilities model-capabilities
568-
:instructions (f.prompt/title-prompt)
569-
:user-messages user-messages
570-
:config config
571-
:tools []
572-
:provider-auth provider-auth})]
573-
(let [title (subs title 0 (min (count title) 30))]
574-
(swap! db* assoc-in [:chats chat-id :title] title)
575-
(send-content! chat-ctx :system (assoc-some
576-
{:type :metadata}
577-
:title title))
578-
;; user prompt responded faster than title was generated
579-
(when (= :idle (get-in @db* [:chats chat-id :status]))
580-
(db/update-workspaces-cache! @db* metrics))))))
564+
(when-let [{:keys [result]} (llm-api/sync-prompt!
565+
{:provider provider
566+
:model model
567+
:model-capabilities model-capabilities
568+
:instructions (f.prompt/title-prompt)
569+
:user-messages user-messages
570+
:config config
571+
:tools []
572+
:provider-auth provider-auth})]
573+
(when result
574+
(let [title (subs result 0 (min (count result) 30))]
575+
(swap! db* assoc-in [:chats chat-id :title] title)
576+
(send-content! chat-ctx :system (assoc-some
577+
{:type :metadata}
578+
:title title))
579+
;; user prompt responded faster than title was generated
580+
(when (= :idle (get-in @db* [:chats chat-id :status]))
581+
(db/update-workspaces-cache! @db* metrics)))))))
581582
(send-content! chat-ctx :system {:type :progress
582583
:state :running
583584
:text "Waiting model"})
584-
(llm-api/complete!
585+
(llm-api/async-prompt!
585586
{:model model
586587
:provider provider
587588
:model-capabilities model-capabilities

0 commit comments

Comments
 (0)