Skip to content
This repository was archived by the owner on Nov 24, 2025. It is now read-only.

Commit ab07111

Browse files
authored
symmetry as provider (#456)
* initail commit * works * better * wdaf * symmetry as provider * 3.22.20
1 parent a81fb37 commit ab07111

21 files changed

+223
-349
lines changed

package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "twinny",
33
"displayName": "twinny - AI Code Completion and Chat",
44
"description": "Locally hosted AI code completion plugin for vscode",
5-
"version": "3.22.19",
5+
"version": "3.22.20",
66
"icon": "assets/icon.png",
77
"keywords": [
88
"code-inference",
@@ -89,18 +89,13 @@
8989
{
9090
"command": "twinny.openChat",
9191
"group": "navigation@0",
92-
"when": "view == twinny.sidebar && twinnyManageTemplates || view == twinny.sidebar && twinnyManageProviders || view == twinny.sidebar && twinnyConversationHistory || view == twinny.sidebar && twinnySymmetryTab || view == twinny.sidebar && twinnyReviewTab || view == twinny.sidebar && twinnyEmbeddingsTab"
92+
"when": "view == twinny.sidebar && twinnyManageTemplates || view == twinny.sidebar && twinnyManageProviders || view == twinny.sidebar && twinnyConversationHistory || view == twinny.sidebar && twinnyReviewTab || view == twinny.sidebar && twinnyEmbeddingsTab"
9393
},
9494
{
9595
"command": "twinny.review",
9696
"group": "navigation@1",
9797
"when": "view == twinny.sidebar"
9898
},
99-
{
100-
"command": "twinny.symmetry",
101-
"group": "navigation@2",
102-
"when": "view == twinny.sidebar"
103-
},
10499
{
105100
"command": "twinny.manageProviders",
106101
"group": "navigation@3",
@@ -191,12 +186,6 @@
191186
"title": "Code reviewer",
192187
"icon": "$(git-pull-request)"
193188
},
194-
{
195-
"command": "twinny.symmetry",
196-
"shortTitle": "twinny symmetry network",
197-
"title": "Symmetry network settings",
198-
"icon": "$(mirror-public)"
199-
},
200189
{
201190
"command": "twinny.conversationHistory",
202191
"shortTitle": "twinny conversation history",
@@ -536,7 +525,7 @@
536525
"rehype-raw": "^7.0.0",
537526
"remark-gfm": "^4.0.0",
538527
"string_score": "^0.1.22",
539-
"symmetry-core": "^1.0.42",
528+
"symmetry-core": "^1.0.43",
540529
"tippy.js": "^6.3.7",
541530
"tiptap-markdown": "^0.8.10",
542531
"toxe": "^1.1.0",

src/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export const OPEN_AI_COMPATIBLE_PROVIDERS = {
131131
Oobabooga: "oobabooga",
132132
OpenWebUI: "openwebui",
133133
Ollama: "ollama",
134+
Twinny: "twinny",
134135
OpenAICompatible: "openai-compatible"
135136
}
136137

src/common/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { ChatCompletionMessageParam } from "fluency.js"
2+
import { CompletionStreaming, LLMProvider } from "fluency.js/dist/chat"
23
import { serverMessageKeys } from "symmetry-core"
34
import { InlineCompletionItem, InlineCompletionList, Uri } from "vscode"
45

@@ -109,7 +110,10 @@ export interface GithubPullRequestMessage {
109110

110111
export type ChatCompletionMessage = ChatCompletionMessageParam & {
111112
id?: string
112-
excludeFromApi?: boolean
113+
}
114+
115+
export type CompletionStreamingWithId = CompletionStreaming<LLMProvider> & {
116+
id?: string
113117
}
114118

115119
export interface Conversation {

src/extension/chat.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { logger } from "../common/logger"
3838
import { models } from "../common/models"
3939
import {
4040
ChatCompletionMessage,
41+
CompletionStreamingWithId,
4142
ContextFile,
4243
FileContextItem,
4344
ServerMessage,
@@ -353,7 +354,7 @@ export class Chat extends Base {
353354
}
354355
}
355356

356-
private async llmStream(requestBody: CompletionStreaming<LLMProvider>) {
357+
private async llmStream(requestBody: CompletionStreamingWithId) {
357358
this._controller = new AbortController()
358359

359360
this._lastStreamingRequest = requestBody
@@ -555,12 +556,14 @@ export class Chat extends Base {
555556

556557
private async buildConversation(
557558
messages: ChatCompletionMessage[],
558-
fileContexts: FileContextItem[] | undefined
559+
fileContexts: FileContextItem[] | undefined,
560+
id?: string // Add parameter for conversation ID
559561
): Promise<ChatCompletionMessage[]> {
560562

561563
const systemMessage: ChatCompletionMessage = {
562564
role: SYSTEM,
563-
content: await this.getSystemPrompt()
565+
content: await this.getSystemPrompt(),
566+
id // Add conversation ID to system message
564567
}
565568

566569
const lastMessage = messages[messages.length - 1]
@@ -576,16 +579,24 @@ export class Chat extends Base {
576579

577580
conversation.push({
578581
role: USER,
579-
content: `${lastMessage.content}\n\n${additionalContext.trim()}`.trim() || " "
582+
content: `${lastMessage.content}\n\n${additionalContext.trim()}`.trim() || " ",
583+
id // Add conversation ID to user message
580584
})
581585

582586
return conversation.map((message) => {
583587
const stringContent = message.content as string
584588

585-
if ([SYSTEM, ASSISTANT].includes(message.role)) return message
589+
if ([SYSTEM, ASSISTANT].includes(message.role)) {
590+
// Preserve the conversationId if it exists
591+
return {
592+
...message,
593+
conversationId: id || message.id
594+
}
595+
}
586596

587597
return {
588598
...message,
599+
conversationId: id || message.id, // Preserve the conversationId
589600
content: stringContent.replace(/&lt;/g, "<")
590601
.replace(/@problems/g, "").trim()
591602
.replace(/@workspace/g, "").trim()
@@ -606,12 +617,14 @@ export class Chat extends Base {
606617
}
607618

608619
private getStreamOptions(
609-
provider: TwinnyProvider
610-
): CompletionStreaming<LLMProvider> {
620+
provider: TwinnyProvider,
621+
conversationId?: string
622+
): CompletionStreamingWithId {
611623
return {
612624
messages: this._conversation,
613625
model: provider.modelName,
614626
stream: true,
627+
id: conversationId,
615628
// eslint-disable-next-line @typescript-eslint/no-explicit-any
616629
provider: this.getProviderType(provider) as any
617630
}
@@ -692,12 +705,15 @@ export class Chat extends Base {
692705

693706
public async completion(
694707
messages: ChatCompletionMessage[],
695-
fileContexts?: FileContextItem[]
708+
fileContexts?: FileContextItem[],
709+
conversationId?: string // Add parameter for conversation ID
696710
) {
697711
this._completion = ""
698712
this._isCancelled = false
699713
this.sendEditorLanguage()
700714

715+
// Debug log to track the conversation ID being received
716+
console.log("Received completion request with conversation ID:", conversationId)
701717

702718
const provider = this.getProvider()
703719

@@ -708,12 +724,13 @@ export class Chat extends Base {
708724
this._conversation = await this.buildConversation(
709725
messages,
710726
fileContexts,
727+
conversationId // Pass the conversation ID to buildConversation
711728
)
712729

713730
const stream = this.shouldUseStreaming(provider)
714731

715732
return stream
716-
? this.llmStream(this.getStreamOptions(provider))
733+
? this.llmStream(this.getStreamOptions(provider, conversationId))
717734
: this.llmNoStream(this.getNoStreamOptions(provider))
718735
}
719736

src/extension/conversation-history.ts

Lines changed: 14 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { ChatCompletionMessageParam } from "fluency.js"
2-
import { v4 as uuidv4 } from "uuid"
32
import { ExtensionContext, Webview } from "vscode"
43

54
import {
@@ -12,27 +11,18 @@ import { ClientMessage, Conversation, ServerMessage } from "../common/types"
1211

1312
import { Base } from "./base"
1413
import { TwinnyProvider } from "./provider-manager"
15-
import { SessionManager } from "./session-manager"
16-
import { SymmetryService } from "./symmetry-service"
1714

1815
type Conversations = Record<string, Conversation> | undefined
1916

2017
export class ConversationHistory extends Base {
2118
public webView: Webview
22-
private _sessionManager: SessionManager | undefined
23-
private _symmetryService: SymmetryService
24-
private _title = ""
2519

2620
constructor(
2721
context: ExtensionContext,
2822
webView: Webview,
29-
sessionManager: SessionManager | undefined,
30-
symmetryService: SymmetryService
3123
) {
3224
super(context)
3325
this.webView = webView
34-
this._sessionManager = sessionManager
35-
this._symmetryService = symmetryService
3626
this.setUpEventListeners()
3727
}
3828

@@ -85,13 +75,11 @@ export class ConversationHistory extends Base {
8575
}
8676
}
8777

88-
async getConversationTitle(
78+
getConversationTitle(
8979
messages: ChatCompletionMessageParam[]
90-
): Promise<string | null> {
91-
80+
):string | undefined {
9281
const message = messages[0].content as string
93-
94-
return Promise.resolve(`${message?.substring(0, 50)}...`)
82+
return `${message?.substring(0, 50)}...`
9583
}
9684

9785
getAllConversations() {
@@ -115,12 +103,15 @@ export class ConversationHistory extends Base {
115103
}
116104

117105
updateConversation(conversation: Conversation) {
118-
const conversations = this.getConversations() || {}
119106
if (!conversation.id) return
107+
108+
const conversations = this.getConversations() || {}
109+
120110
this.context?.globalState.update(CONVERSATION_STORAGE_KEY, {
121111
...conversations,
122112
[conversation.id]: conversation
123113
})
114+
124115
this.setActiveConversation(conversation)
125116
}
126117

@@ -129,16 +120,19 @@ export class ConversationHistory extends Base {
129120
ACTIVE_CONVERSATION_STORAGE_KEY,
130121
conversation
131122
)
123+
132124
this.webView?.postMessage({
133125
type: CONVERSATION_EVENT_NAME.setActiveConversation,
134126
data: conversation
135127
} as ServerMessage<Conversation>)
128+
136129
this.getAllConversations()
137130
}
138131

139132
getActiveConversation() {
140133
const conversation: Conversation | undefined =
141134
this.context?.globalState.get(ACTIVE_CONVERSATION_STORAGE_KEY)
135+
142136
this.setActiveConversation(conversation)
143137
return conversation
144138
}
@@ -161,31 +155,13 @@ export class ConversationHistory extends Base {
161155

162156
async saveConversation(conversation: Conversation) {
163157
const activeConversation = this.getActiveConversation()
164-
if (activeConversation)
158+
159+
if (activeConversation) {
165160
return this.updateConversation({
166161
...activeConversation,
167-
messages: conversation.messages
162+
messages: conversation.messages,
163+
title: this.getConversationTitle(conversation.messages)
168164
})
169-
170-
if (!conversation.messages.length || conversation.messages.length > 2)
171-
return
172-
173-
this._title = await this.getConversationTitle(conversation.messages) || " "
174-
this.saveConversationEnd(conversation)
175-
}
176-
177-
private saveConversationEnd(conversation: Conversation) {
178-
const id = uuidv4()
179-
const conversations = this.getConversations()
180-
if (!conversations) return
181-
const newConversation: Conversation = {
182-
id,
183-
title: this._title || "",
184-
messages: conversation.messages
185165
}
186-
conversations[id] = newConversation
187-
this.context?.globalState.update(CONVERSATION_STORAGE_KEY, conversations)
188-
this.setActiveConversation(newConversation)
189-
this._title = ""
190166
}
191167
}

src/extension/provider-manager.ts

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,13 @@ export class ProviderManager {
9393

9494
getDefaultChatProvider() {
9595
return {
96-
apiHostname: "0.0.0.0",
96+
apiHostname: "twinny.dev",
9797
apiPath: "/v1",
98-
apiPort: 11434,
99-
apiProtocol: "http",
100-
id: uuidv4(),
101-
label: "OpenAI Compatible (localhost)",
102-
modelName: "codellama:7b-instruct",
103-
provider: API_PROVIDERS.Ollama,
98+
apiProtocol: "https",
99+
id: "symmetry-default",
100+
label: "Twinny.dev (Symmetry)",
101+
modelName: "llama3.2:latest",
102+
provider: API_PROVIDERS.Twinny,
104103
type: "chat",
105104
} as TwinnyProvider
106105
}

src/extension/providers/base.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,6 @@ export class BaseProvider {
102102
this.conversationHistory = new ConversationHistory(
103103
this.context,
104104
this.webView,
105-
this._sessionManager,
106-
this._symmetryService
107105
)
108106

109107
this.reviewService = new ReviewService(
@@ -422,7 +420,11 @@ export class BaseProvider {
422420
)
423421
}
424422

425-
this.chat?.completion(data.data || [], data.meta as FileContextItem[])
423+
this.chat?.completion(
424+
data.data || [],
425+
data.meta as FileContextItem[],
426+
data.key // Pass the conversation ID
427+
)
426428
}
427429

428430
private getSelectedText = () => {

0 commit comments

Comments
 (0)