@stina/extension-api 0.21.0 → 0.22.1
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.
- package/dist/{chunk-WIDGIYRV.js → chunk-U3PEHSBG.js} +1 -1
- package/dist/chunk-U3PEHSBG.js.map +1 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +67 -6
- package/dist/index.d.ts +67 -6
- package/dist/index.js +1 -1
- package/dist/runtime.cjs +242 -0
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +243 -1
- package/dist/runtime.js.map +1 -1
- package/dist/{types.tools-BQrCW_wq.d.cts → types.tools-BXGZf8zc.d.cts} +188 -1
- package/dist/{types.tools-BQrCW_wq.d.ts → types.tools-BXGZf8zc.d.ts} +188 -1
- package/package.json +1 -1
- package/src/background.test.ts +525 -0
- package/src/background.ts +261 -0
- package/src/index.ts +14 -0
- package/src/messages.ts +71 -0
- package/src/runtime.ts +113 -0
- package/src/types.context.ts +217 -0
- package/src/types.permissions.ts +1 -0
- package/src/types.ts +7 -0
- package/dist/chunk-WIDGIYRV.js.map +0 -1
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background Task Manager (Worker-side)
|
|
3
|
+
*
|
|
4
|
+
* Manages background tasks running inside the extension worker.
|
|
5
|
+
* Handles task execution, AbortController management, and health reporting.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
BackgroundTaskConfig,
|
|
10
|
+
BackgroundTaskCallback,
|
|
11
|
+
BackgroundTaskContext,
|
|
12
|
+
BackgroundTaskHealth,
|
|
13
|
+
Disposable,
|
|
14
|
+
LogAPI,
|
|
15
|
+
} from './types.js'
|
|
16
|
+
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Types
|
|
19
|
+
// ============================================================================
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Internal representation of a registered task
|
|
23
|
+
*/
|
|
24
|
+
interface RegisteredTask {
|
|
25
|
+
config: BackgroundTaskConfig
|
|
26
|
+
callback: BackgroundTaskCallback
|
|
27
|
+
abortController: AbortController | null
|
|
28
|
+
status: 'pending' | 'running' | 'stopped' | 'failed'
|
|
29
|
+
lastHealthStatus?: string
|
|
30
|
+
lastHealthTime?: string
|
|
31
|
+
error?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Options for the WorkerBackgroundTaskManager
|
|
36
|
+
*/
|
|
37
|
+
export interface WorkerBackgroundTaskManagerOptions {
|
|
38
|
+
extensionId: string
|
|
39
|
+
extensionVersion: string
|
|
40
|
+
storagePath: string
|
|
41
|
+
/** Send a message to the host */
|
|
42
|
+
sendTaskRegistered: (
|
|
43
|
+
taskId: string,
|
|
44
|
+
name: string,
|
|
45
|
+
userId: string,
|
|
46
|
+
restartPolicy: BackgroundTaskConfig['restartPolicy'],
|
|
47
|
+
payload?: Record<string, unknown>
|
|
48
|
+
) => void
|
|
49
|
+
/** Send status update to host */
|
|
50
|
+
sendTaskStatus: (taskId: string, status: 'running' | 'stopped' | 'failed', error?: string) => void
|
|
51
|
+
/** Send health report to host */
|
|
52
|
+
sendHealthReport: (taskId: string, status: string, timestamp: string) => void
|
|
53
|
+
/** Create a log API for a task */
|
|
54
|
+
createLogAPI: (taskId: string) => LogAPI
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// WorkerBackgroundTaskManager
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Manages background tasks within the extension worker.
|
|
63
|
+
*/
|
|
64
|
+
export class WorkerBackgroundTaskManager {
|
|
65
|
+
private readonly tasks = new Map<string, RegisteredTask>()
|
|
66
|
+
private readonly options: WorkerBackgroundTaskManagerOptions
|
|
67
|
+
|
|
68
|
+
constructor(options: WorkerBackgroundTaskManagerOptions) {
|
|
69
|
+
this.options = options
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Register and start a background task.
|
|
74
|
+
* @returns A disposable that stops the task when disposed
|
|
75
|
+
*/
|
|
76
|
+
async start(config: BackgroundTaskConfig, callback: BackgroundTaskCallback): Promise<Disposable> {
|
|
77
|
+
const { id: taskId } = config
|
|
78
|
+
|
|
79
|
+
if (this.tasks.has(taskId)) {
|
|
80
|
+
throw new Error(`Background task with id '${taskId}' is already registered`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const task: RegisteredTask = {
|
|
84
|
+
config,
|
|
85
|
+
callback,
|
|
86
|
+
abortController: null,
|
|
87
|
+
status: 'pending',
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
this.tasks.set(taskId, task)
|
|
91
|
+
|
|
92
|
+
// Notify host about the registration
|
|
93
|
+
this.options.sendTaskRegistered(
|
|
94
|
+
taskId,
|
|
95
|
+
config.name,
|
|
96
|
+
config.userId,
|
|
97
|
+
config.restartPolicy,
|
|
98
|
+
config.payload
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
// Return a disposable that stops the task
|
|
102
|
+
// Task removal should be coordinated with the host to avoid race conditions
|
|
103
|
+
return {
|
|
104
|
+
dispose: () => {
|
|
105
|
+
this.stop(taskId)
|
|
106
|
+
// Don't immediately delete - let the task finish aborting
|
|
107
|
+
// The task will be cleaned up when the extension is deactivated
|
|
108
|
+
},
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Stop a running task.
|
|
114
|
+
*/
|
|
115
|
+
stop(taskId: string): void {
|
|
116
|
+
const task = this.tasks.get(taskId)
|
|
117
|
+
if (!task) {
|
|
118
|
+
return
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Abort the task if it's running
|
|
122
|
+
if (task.abortController) {
|
|
123
|
+
task.abortController.abort()
|
|
124
|
+
task.abortController = null
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
task.status = 'stopped'
|
|
128
|
+
|
|
129
|
+
// Notify host that the task has been stopped
|
|
130
|
+
this.options.sendTaskStatus(taskId, 'stopped')
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Handle start message from host.
|
|
135
|
+
* This is called when the host tells us to actually run the task.
|
|
136
|
+
*/
|
|
137
|
+
async handleStart(taskId: string): Promise<void> {
|
|
138
|
+
const task = this.tasks.get(taskId)
|
|
139
|
+
if (!task) {
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// If there's already an execution running, abort it first
|
|
144
|
+
if (task.abortController) {
|
|
145
|
+
task.abortController.abort()
|
|
146
|
+
task.abortController = null
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Create new AbortController for this run
|
|
150
|
+
task.abortController = new AbortController()
|
|
151
|
+
task.status = 'running'
|
|
152
|
+
task.error = undefined
|
|
153
|
+
|
|
154
|
+
// Build the task context
|
|
155
|
+
const context = this.buildTaskContext(task)
|
|
156
|
+
|
|
157
|
+
// Notify host that we're running
|
|
158
|
+
this.options.sendTaskStatus(taskId, 'running')
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
// Execute the callback
|
|
162
|
+
await task.callback(context)
|
|
163
|
+
|
|
164
|
+
// Task completed normally (or was aborted)
|
|
165
|
+
if (task.abortController?.signal.aborted) {
|
|
166
|
+
task.status = 'stopped'
|
|
167
|
+
this.options.sendTaskStatus(taskId, 'stopped')
|
|
168
|
+
} else {
|
|
169
|
+
// Task finished without being aborted - treat as stopped
|
|
170
|
+
task.status = 'stopped'
|
|
171
|
+
this.options.sendTaskStatus(taskId, 'stopped')
|
|
172
|
+
}
|
|
173
|
+
} catch (error) {
|
|
174
|
+
// Task failed with an error
|
|
175
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
176
|
+
task.status = 'failed'
|
|
177
|
+
task.error = errorMessage
|
|
178
|
+
this.options.sendTaskStatus(taskId, 'failed', errorMessage)
|
|
179
|
+
} finally {
|
|
180
|
+
task.abortController = null
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Handle stop message from host.
|
|
186
|
+
*/
|
|
187
|
+
handleStop(taskId: string): void {
|
|
188
|
+
this.stop(taskId)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Build the execution context for a task.
|
|
193
|
+
*/
|
|
194
|
+
private buildTaskContext(task: RegisteredTask): BackgroundTaskContext {
|
|
195
|
+
const { config, abortController } = task
|
|
196
|
+
const signal = abortController!.signal
|
|
197
|
+
|
|
198
|
+
const log = this.options.createLogAPI(config.id)
|
|
199
|
+
|
|
200
|
+
const context: BackgroundTaskContext = {
|
|
201
|
+
userId: config.userId,
|
|
202
|
+
extension: {
|
|
203
|
+
id: this.options.extensionId,
|
|
204
|
+
version: this.options.extensionVersion,
|
|
205
|
+
storagePath: this.options.storagePath,
|
|
206
|
+
},
|
|
207
|
+
signal,
|
|
208
|
+
reportHealth: (status: string) => {
|
|
209
|
+
const timestamp = new Date().toISOString()
|
|
210
|
+
task.lastHealthStatus = status
|
|
211
|
+
task.lastHealthTime = timestamp
|
|
212
|
+
this.options.sendHealthReport(config.id, status, timestamp)
|
|
213
|
+
},
|
|
214
|
+
log,
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return context
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Get the status of all tasks.
|
|
222
|
+
*/
|
|
223
|
+
getStatus(): BackgroundTaskHealth[] {
|
|
224
|
+
const result: BackgroundTaskHealth[] = []
|
|
225
|
+
|
|
226
|
+
for (const task of this.tasks.values()) {
|
|
227
|
+
result.push({
|
|
228
|
+
taskId: task.config.id,
|
|
229
|
+
name: task.config.name,
|
|
230
|
+
userId: task.config.userId,
|
|
231
|
+
status: task.status,
|
|
232
|
+
restartCount: 0, // Worker doesn't track restarts, host does
|
|
233
|
+
lastHealthStatus: task.lastHealthStatus,
|
|
234
|
+
lastHealthTime: task.lastHealthTime,
|
|
235
|
+
error: task.error,
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return result
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Check if a task exists.
|
|
244
|
+
*/
|
|
245
|
+
hasTask(taskId: string): boolean {
|
|
246
|
+
return this.tasks.has(taskId)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Clean up all tasks.
|
|
251
|
+
* Called during extension deactivation.
|
|
252
|
+
*/
|
|
253
|
+
dispose(): void {
|
|
254
|
+
for (const task of this.tasks.values()) {
|
|
255
|
+
if (task.abortController) {
|
|
256
|
+
task.abortController.abort()
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
this.tasks.clear()
|
|
260
|
+
}
|
|
261
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -73,6 +73,14 @@ export type {
|
|
|
73
73
|
StorageAPI,
|
|
74
74
|
LogAPI,
|
|
75
75
|
|
|
76
|
+
// Background workers
|
|
77
|
+
BackgroundWorkersAPI,
|
|
78
|
+
BackgroundTaskConfig,
|
|
79
|
+
BackgroundTaskCallback,
|
|
80
|
+
BackgroundTaskContext,
|
|
81
|
+
BackgroundTaskHealth,
|
|
82
|
+
BackgroundRestartPolicy,
|
|
83
|
+
|
|
76
84
|
// AI Provider
|
|
77
85
|
AIProvider,
|
|
78
86
|
ModelInfo,
|
|
@@ -117,6 +125,12 @@ export type {
|
|
|
117
125
|
StreamEventMessage,
|
|
118
126
|
LogMessage,
|
|
119
127
|
PendingRequest,
|
|
128
|
+
// Background task messages
|
|
129
|
+
BackgroundTaskStartMessage,
|
|
130
|
+
BackgroundTaskStopMessage,
|
|
131
|
+
BackgroundTaskRegisteredMessage,
|
|
132
|
+
BackgroundTaskStatusMessage,
|
|
133
|
+
BackgroundTaskHealthMessage,
|
|
120
134
|
} from './messages.js'
|
|
121
135
|
|
|
122
136
|
export { generateMessageId } from './messages.js'
|
package/src/messages.ts
CHANGED
|
@@ -28,6 +28,8 @@ export type HostToWorkerMessage =
|
|
|
28
28
|
| ActionExecuteRequestMessage
|
|
29
29
|
| ResponseMessage
|
|
30
30
|
| StreamingFetchChunkMessage
|
|
31
|
+
| BackgroundTaskStartMessage
|
|
32
|
+
| BackgroundTaskStopMessage
|
|
31
33
|
|
|
32
34
|
export interface ActivateMessage {
|
|
33
35
|
type: 'activate'
|
|
@@ -128,6 +130,28 @@ export interface StreamingFetchChunkMessage {
|
|
|
128
130
|
}
|
|
129
131
|
}
|
|
130
132
|
|
|
133
|
+
/**
|
|
134
|
+
* Message sent from host to worker to start a registered background task.
|
|
135
|
+
*/
|
|
136
|
+
export interface BackgroundTaskStartMessage {
|
|
137
|
+
type: 'background-task-start'
|
|
138
|
+
id: string
|
|
139
|
+
payload: {
|
|
140
|
+
taskId: string
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Message sent from host to worker to stop a running background task.
|
|
146
|
+
*/
|
|
147
|
+
export interface BackgroundTaskStopMessage {
|
|
148
|
+
type: 'background-task-stop'
|
|
149
|
+
id: string
|
|
150
|
+
payload: {
|
|
151
|
+
taskId: string
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
131
155
|
// ============================================================================
|
|
132
156
|
// Worker → Host Messages
|
|
133
157
|
// ============================================================================
|
|
@@ -144,6 +168,9 @@ export type WorkerToHostMessage =
|
|
|
144
168
|
| ToolExecuteResponseMessage
|
|
145
169
|
| ActionExecuteResponseMessage
|
|
146
170
|
| StreamingFetchAckMessage
|
|
171
|
+
| BackgroundTaskRegisteredMessage
|
|
172
|
+
| BackgroundTaskStatusMessage
|
|
173
|
+
| BackgroundTaskHealthMessage
|
|
147
174
|
|
|
148
175
|
export interface ReadyMessage {
|
|
149
176
|
type: 'ready'
|
|
@@ -257,6 +284,50 @@ export interface LogMessage {
|
|
|
257
284
|
}
|
|
258
285
|
}
|
|
259
286
|
|
|
287
|
+
/**
|
|
288
|
+
* Message sent from worker to host when a background task is registered.
|
|
289
|
+
*/
|
|
290
|
+
export interface BackgroundTaskRegisteredMessage {
|
|
291
|
+
type: 'background-task-registered'
|
|
292
|
+
payload: {
|
|
293
|
+
taskId: string
|
|
294
|
+
name: string
|
|
295
|
+
userId: string
|
|
296
|
+
restartPolicy: {
|
|
297
|
+
type: 'always' | 'on-failure' | 'never'
|
|
298
|
+
maxRestarts?: number
|
|
299
|
+
initialDelayMs?: number
|
|
300
|
+
maxDelayMs?: number
|
|
301
|
+
backoffMultiplier?: number
|
|
302
|
+
}
|
|
303
|
+
payload?: Record<string, unknown>
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Message sent from worker to host with background task status updates.
|
|
309
|
+
*/
|
|
310
|
+
export interface BackgroundTaskStatusMessage {
|
|
311
|
+
type: 'background-task-status'
|
|
312
|
+
payload: {
|
|
313
|
+
taskId: string
|
|
314
|
+
status: 'running' | 'stopped' | 'failed'
|
|
315
|
+
error?: string
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Message sent from worker to host with background task health reports.
|
|
321
|
+
*/
|
|
322
|
+
export interface BackgroundTaskHealthMessage {
|
|
323
|
+
type: 'background-task-health'
|
|
324
|
+
payload: {
|
|
325
|
+
taskId: string
|
|
326
|
+
status: string
|
|
327
|
+
timestamp: string
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
260
331
|
// ============================================================================
|
|
261
332
|
// Utility Types
|
|
262
333
|
// ============================================================================
|
package/src/runtime.ts
CHANGED
|
@@ -32,8 +32,14 @@ import type {
|
|
|
32
32
|
ChatMessage,
|
|
33
33
|
ChatOptions,
|
|
34
34
|
GetModelsOptions,
|
|
35
|
+
BackgroundWorkersAPI,
|
|
36
|
+
BackgroundTaskConfig,
|
|
37
|
+
BackgroundTaskCallback,
|
|
38
|
+
BackgroundTaskHealth,
|
|
35
39
|
} from './types.js'
|
|
36
40
|
|
|
41
|
+
import { WorkerBackgroundTaskManager } from './background.js'
|
|
42
|
+
|
|
37
43
|
import type {
|
|
38
44
|
HostToWorkerMessage,
|
|
39
45
|
WorkerToHostMessage,
|
|
@@ -88,6 +94,7 @@ const messagePort = getMessagePort()
|
|
|
88
94
|
let extensionModule: ExtensionModule | null = null
|
|
89
95
|
let extensionDisposable: Disposable | null = null
|
|
90
96
|
let extensionContext: ExtensionContext | null = null
|
|
97
|
+
let backgroundTaskManager: WorkerBackgroundTaskManager | null = null
|
|
91
98
|
|
|
92
99
|
const pendingRequests = new Map<string, PendingRequest>()
|
|
93
100
|
const registeredProviders = new Map<string, AIProvider>()
|
|
@@ -188,6 +195,14 @@ async function handleHostMessage(message: HostToWorkerMessage): Promise<void> {
|
|
|
188
195
|
case 'streaming-fetch-chunk':
|
|
189
196
|
handleStreamingFetchChunk(message.payload)
|
|
190
197
|
break
|
|
198
|
+
|
|
199
|
+
case 'background-task-start':
|
|
200
|
+
await handleBackgroundTaskStart(message.payload.taskId)
|
|
201
|
+
break
|
|
202
|
+
|
|
203
|
+
case 'background-task-stop':
|
|
204
|
+
handleBackgroundTaskStop(message.payload.taskId)
|
|
205
|
+
break
|
|
191
206
|
}
|
|
192
207
|
}
|
|
193
208
|
|
|
@@ -284,12 +299,16 @@ async function handleDeactivate(): Promise<void> {
|
|
|
284
299
|
if (extensionDisposable) {
|
|
285
300
|
extensionDisposable.dispose()
|
|
286
301
|
}
|
|
302
|
+
if (backgroundTaskManager) {
|
|
303
|
+
backgroundTaskManager.dispose()
|
|
304
|
+
}
|
|
287
305
|
} catch (error) {
|
|
288
306
|
console.error('Error during deactivation:', error)
|
|
289
307
|
} finally {
|
|
290
308
|
extensionModule = null
|
|
291
309
|
extensionDisposable = null
|
|
292
310
|
extensionContext = null
|
|
311
|
+
backgroundTaskManager = null
|
|
293
312
|
registeredProviders.clear()
|
|
294
313
|
registeredTools.clear()
|
|
295
314
|
registeredActions.clear()
|
|
@@ -332,6 +351,26 @@ async function handleSchedulerFire(payload: SchedulerFirePayload): Promise<void>
|
|
|
332
351
|
})
|
|
333
352
|
}
|
|
334
353
|
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// Background Task Handlers
|
|
356
|
+
// ============================================================================
|
|
357
|
+
|
|
358
|
+
async function handleBackgroundTaskStart(taskId: string): Promise<void> {
|
|
359
|
+
if (!backgroundTaskManager) {
|
|
360
|
+
console.error('Background task manager not initialized')
|
|
361
|
+
return
|
|
362
|
+
}
|
|
363
|
+
await backgroundTaskManager.handleStart(taskId)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function handleBackgroundTaskStop(taskId: string): void {
|
|
367
|
+
if (!backgroundTaskManager) {
|
|
368
|
+
console.error('Background task manager not initialized')
|
|
369
|
+
return
|
|
370
|
+
}
|
|
371
|
+
backgroundTaskManager.handleStop(taskId)
|
|
372
|
+
}
|
|
373
|
+
|
|
335
374
|
// ============================================================================
|
|
336
375
|
// Provider / Tool Requests
|
|
337
376
|
// ============================================================================
|
|
@@ -826,6 +865,73 @@ function buildContext(
|
|
|
826
865
|
;(context as { storage: StorageAPI }).storage = storageApi
|
|
827
866
|
}
|
|
828
867
|
|
|
868
|
+
// Add background workers API if permitted
|
|
869
|
+
if (hasPermission('background.workers')) {
|
|
870
|
+
// Initialize the background task manager if not already done
|
|
871
|
+
if (!backgroundTaskManager) {
|
|
872
|
+
backgroundTaskManager = new WorkerBackgroundTaskManager({
|
|
873
|
+
extensionId,
|
|
874
|
+
extensionVersion,
|
|
875
|
+
storagePath,
|
|
876
|
+
sendTaskRegistered: (taskId, name, userId, restartPolicy, payload) => {
|
|
877
|
+
postMessage({
|
|
878
|
+
type: 'background-task-registered',
|
|
879
|
+
payload: {
|
|
880
|
+
taskId,
|
|
881
|
+
name,
|
|
882
|
+
userId,
|
|
883
|
+
restartPolicy,
|
|
884
|
+
payload,
|
|
885
|
+
},
|
|
886
|
+
})
|
|
887
|
+
},
|
|
888
|
+
sendTaskStatus: (taskId, status, error) => {
|
|
889
|
+
postMessage({
|
|
890
|
+
type: 'background-task-status',
|
|
891
|
+
payload: {
|
|
892
|
+
taskId,
|
|
893
|
+
status,
|
|
894
|
+
error,
|
|
895
|
+
},
|
|
896
|
+
})
|
|
897
|
+
},
|
|
898
|
+
sendHealthReport: (taskId, status, timestamp) => {
|
|
899
|
+
postMessage({
|
|
900
|
+
type: 'background-task-health',
|
|
901
|
+
payload: {
|
|
902
|
+
taskId,
|
|
903
|
+
status,
|
|
904
|
+
timestamp,
|
|
905
|
+
},
|
|
906
|
+
})
|
|
907
|
+
},
|
|
908
|
+
createLogAPI: (taskId) => ({
|
|
909
|
+
debug: (message, data) =>
|
|
910
|
+
postMessage({ type: 'log', payload: { level: 'debug', message: `[${taskId}] ${message}`, data } }),
|
|
911
|
+
info: (message, data) =>
|
|
912
|
+
postMessage({ type: 'log', payload: { level: 'info', message: `[${taskId}] ${message}`, data } }),
|
|
913
|
+
warn: (message, data) =>
|
|
914
|
+
postMessage({ type: 'log', payload: { level: 'warn', message: `[${taskId}] ${message}`, data } }),
|
|
915
|
+
error: (message, data) =>
|
|
916
|
+
postMessage({ type: 'log', payload: { level: 'error', message: `[${taskId}] ${message}`, data } }),
|
|
917
|
+
}),
|
|
918
|
+
})
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
const backgroundWorkersApi: BackgroundWorkersAPI = {
|
|
922
|
+
async start(config: BackgroundTaskConfig, callback: BackgroundTaskCallback): Promise<Disposable> {
|
|
923
|
+
return backgroundTaskManager!.start(config, callback)
|
|
924
|
+
},
|
|
925
|
+
async stop(taskId: string): Promise<void> {
|
|
926
|
+
backgroundTaskManager!.stop(taskId)
|
|
927
|
+
},
|
|
928
|
+
async getStatus(): Promise<BackgroundTaskHealth[]> {
|
|
929
|
+
return backgroundTaskManager!.getStatus()
|
|
930
|
+
},
|
|
931
|
+
}
|
|
932
|
+
;(context as { backgroundWorkers: BackgroundWorkersAPI }).backgroundWorkers = backgroundWorkersApi
|
|
933
|
+
}
|
|
934
|
+
|
|
829
935
|
return context
|
|
830
936
|
}
|
|
831
937
|
|
|
@@ -871,4 +977,11 @@ export type {
|
|
|
871
977
|
ChatOptions,
|
|
872
978
|
GetModelsOptions,
|
|
873
979
|
StreamEvent,
|
|
980
|
+
// Background workers
|
|
981
|
+
BackgroundWorkersAPI,
|
|
982
|
+
BackgroundTaskConfig,
|
|
983
|
+
BackgroundTaskCallback,
|
|
984
|
+
BackgroundTaskContext,
|
|
985
|
+
BackgroundTaskHealth,
|
|
986
|
+
BackgroundRestartPolicy,
|
|
874
987
|
} from './types.js'
|