kimaki 0.1.4 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,6 +17,7 @@ export interface GenAIWorkerOptions {
17
17
  onAssistantStartSpeaking?: () => void
18
18
  onAssistantStopSpeaking?: () => void
19
19
  onAssistantInterruptSpeaking?: () => void
20
+ onAllSessionsCompleted?: () => void
20
21
  onToolCallCompleted?: (params: {
21
22
  sessionId: string
22
23
  messageId: string
@@ -60,6 +61,9 @@ export function createGenAIWorker(
60
61
  case 'assistantInterruptSpeaking':
61
62
  options.onAssistantInterruptSpeaking?.()
62
63
  break
64
+ case 'allSessionsCompleted':
65
+ options.onAllSessionsCompleted?.()
66
+ break
63
67
  case 'toolCallCompleted':
64
68
  options.onToolCallCompleted?.(message)
65
69
  break
@@ -265,6 +265,11 @@ parentPort.on('message', async (message: WorkerInMessage) => {
265
265
  ...params,
266
266
  } satisfies WorkerOutMessage)
267
267
  },
268
+ onAllSessionsCompleted: () => {
269
+ parentPort!.postMessage({
270
+ type: 'allSessionsCompleted',
271
+ } satisfies WorkerOutMessage)
272
+ },
268
273
  })
269
274
 
270
275
  // Start GenAI session
package/src/tools.ts CHANGED
@@ -19,6 +19,7 @@ import { initializeOpencodeForDirectory } from './discordBot.js'
19
19
 
20
20
  export async function getTools({
21
21
  onMessageCompleted,
22
+ onAllSessionsCompleted,
22
23
  directory,
23
24
  }: {
24
25
  directory: string
@@ -29,6 +30,7 @@ export async function getTools({
29
30
  error?: unknown
30
31
  markdown?: string
31
32
  }) => void
33
+ onAllSessionsCompleted?: () => void
32
34
  }) {
33
35
  const getClient = await initializeOpencodeForDirectory(directory)
34
36
  const client = getClient()
@@ -37,6 +39,9 @@ export async function getTools({
37
39
 
38
40
  const providersResponse = await client.config.providers({})
39
41
  const providers: Provider[] = providersResponse.data?.providers || []
42
+
43
+ // Track all active OpenCode sessions
44
+ const activeSessions = new Set<string>()
40
45
 
41
46
  // Helper: get last assistant model for a session (non-summary)
42
47
  const getSessionModel = async (
@@ -68,6 +73,10 @@ export async function getTools({
68
73
  execute: async ({ sessionId, message }) => {
69
74
  const sessionModel = await getSessionModel(sessionId)
70
75
 
76
+ // Track this session as active
77
+ activeSessions.add(sessionId)
78
+ toolsLogger.log(`Session ${sessionId} started, ${activeSessions.size} active sessions`)
79
+
71
80
  // do not await
72
81
  getClient()
73
82
  .session.prompt({
@@ -89,6 +98,16 @@ export async function getTools({
89
98
  data: response.data,
90
99
  markdown,
91
100
  })
101
+
102
+ // Remove from active sessions
103
+ activeSessions.delete(sessionId)
104
+ toolsLogger.log(`Session ${sessionId} completed, ${activeSessions.size} active sessions remaining`)
105
+
106
+ // Check if all sessions are complete
107
+ if (activeSessions.size === 0) {
108
+ toolsLogger.log('All sessions completed')
109
+ onAllSessionsCompleted?.()
110
+ }
92
111
  })
93
112
  .catch((error) => {
94
113
  onMessageCompleted?.({
@@ -96,6 +115,16 @@ export async function getTools({
96
115
  messageId: '',
97
116
  error,
98
117
  })
118
+
119
+ // Remove from active sessions even on error
120
+ activeSessions.delete(sessionId)
121
+ toolsLogger.log(`Session ${sessionId} failed, ${activeSessions.size} active sessions remaining`)
122
+
123
+ // Check if all sessions are complete
124
+ if (activeSessions.size === 0) {
125
+ toolsLogger.log('All sessions completed')
126
+ onAllSessionsCompleted?.()
127
+ }
99
128
  })
100
129
  return {
101
130
  success: true,
@@ -143,32 +172,58 @@ export async function getTools({
143
172
  throw new Error('Failed to create session')
144
173
  }
145
174
 
175
+ const newSessionId = session.data.id
176
+
177
+ // Track this session as active
178
+ activeSessions.add(newSessionId)
179
+ toolsLogger.log(`New session ${newSessionId} created, ${activeSessions.size} active sessions`)
180
+
146
181
  // do not await
147
182
  getClient()
148
183
  .session.prompt({
149
- path: { id: session.data.id },
184
+ path: { id: newSessionId },
150
185
  body: {
151
186
  parts: [{ type: 'text', text: message }],
152
187
  },
153
188
  })
154
189
  .then(async (response) => {
155
190
  const markdown = await markdownRenderer.generate({
156
- sessionID: session.data.id,
191
+ sessionID: newSessionId,
157
192
  lastAssistantOnly: true,
158
193
  })
159
194
  onMessageCompleted?.({
160
- sessionId: session.data.id,
195
+ sessionId: newSessionId,
161
196
  messageId: '',
162
197
  data: response.data,
163
198
  markdown,
164
199
  })
200
+
201
+ // Remove from active sessions
202
+ activeSessions.delete(newSessionId)
203
+ toolsLogger.log(`Session ${newSessionId} completed, ${activeSessions.size} active sessions remaining`)
204
+
205
+ // Check if all sessions are complete
206
+ if (activeSessions.size === 0) {
207
+ toolsLogger.log('All sessions completed')
208
+ onAllSessionsCompleted?.()
209
+ }
165
210
  })
166
211
  .catch((error) => {
167
212
  onMessageCompleted?.({
168
- sessionId: session.data.id,
213
+ sessionId: newSessionId,
169
214
  messageId: '',
170
215
  error,
171
216
  })
217
+
218
+ // Remove from active sessions even on error
219
+ activeSessions.delete(newSessionId)
220
+ toolsLogger.log(`Session ${newSessionId} failed, ${activeSessions.size} active sessions remaining`)
221
+
222
+ // Check if all sessions are complete
223
+ if (activeSessions.size === 0) {
224
+ toolsLogger.log('All sessions completed')
225
+ onAllSessionsCompleted?.()
226
+ }
172
227
  })
173
228
 
174
229
  return {
@@ -53,6 +53,9 @@ export type WorkerOutMessage =
53
53
  error?: any
54
54
  markdown?: string
55
55
  }
56
+ | {
57
+ type: 'allSessionsCompleted'
58
+ }
56
59
  | {
57
60
  type: 'error'
58
61
  error: string