0g-orbit 0.2.1 → 0.2.3
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/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +151 -0
- package/dist/cli/cli.js +1 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +23 -1
- package/dist/storage.js.map +1 -1
- package/package.json +28 -4
- package/examples/ai-chatbot/index.ts +0 -74
- package/examples/model-registry/index.ts +0 -137
- package/examples/quick-start/index.ts +0 -65
- package/packages/cli/package.json +0 -30
- package/packages/cli/src/cli.ts +0 -69
- package/packages/cli/src/commands/account.ts +0 -29
- package/packages/cli/src/commands/inference.ts +0 -103
- package/packages/cli/src/commands/init.ts +0 -71
- package/packages/cli/src/commands/storage.ts +0 -91
- package/packages/cli/src/utils.ts +0 -21
- package/packages/cli/tsconfig.json +0 -8
- package/packages/core/package.json +0 -35
- package/packages/core/src/errors.test.ts +0 -99
- package/packages/core/src/errors.ts +0 -79
- package/packages/core/src/index.ts +0 -37
- package/packages/core/src/inference.ts +0 -256
- package/packages/core/src/networks.test.ts +0 -62
- package/packages/core/src/networks.ts +0 -62
- package/packages/core/src/orbit.test.ts +0 -153
- package/packages/core/src/orbit.ts +0 -159
- package/packages/core/src/retry.test.ts +0 -99
- package/packages/core/src/retry.ts +0 -99
- package/packages/core/src/storage.test.ts +0 -199
- package/packages/core/src/storage.ts +0 -158
- package/packages/core/src/types.ts +0 -85
- package/packages/core/tsconfig.json +0 -8
- package/packages/core/vitest.config.ts +0 -7
- package/src/cli/cli.ts +0 -95
- package/src/cli/commands/account.ts +0 -29
- package/src/cli/commands/fine-tuning.ts +0 -169
- package/src/cli/commands/inference.ts +0 -103
- package/src/cli/commands/init.ts +0 -71
- package/src/cli/commands/storage.ts +0 -91
- package/src/cli/utils.ts +0 -21
- package/src/errors.test.ts +0 -99
- package/src/errors.ts +0 -90
- package/src/fine-tuning.test.ts +0 -299
- package/src/fine-tuning.ts +0 -330
- package/src/index.ts +0 -45
- package/src/inference.ts +0 -256
- package/src/networks.test.ts +0 -62
- package/src/networks.ts +0 -62
- package/src/orbit.test.ts +0 -153
- package/src/orbit.ts +0 -204
- package/src/retry.test.ts +0 -99
- package/src/retry.ts +0 -99
- package/src/storage.test.ts +0 -199
- package/src/storage.ts +0 -158
- package/src/types.ts +0 -157
- package/tsconfig.json +0 -20
- package/vitest.config.ts +0 -7
package/src/errors.ts
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
export class OrbitError extends Error {
|
|
2
|
-
constructor(
|
|
3
|
-
message: string,
|
|
4
|
-
public readonly code: string,
|
|
5
|
-
public readonly suggestion?: string
|
|
6
|
-
) {
|
|
7
|
-
super(message)
|
|
8
|
-
this.name = 'OrbitError'
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export class ConnectionError extends OrbitError {
|
|
13
|
-
constructor(message: string, suggestion?: string) {
|
|
14
|
-
super(
|
|
15
|
-
message,
|
|
16
|
-
'CONNECTION_ERROR',
|
|
17
|
-
suggestion ?? 'Check your RPC URL and network connection. Try a different RPC endpoint with the rpcUrl option.'
|
|
18
|
-
)
|
|
19
|
-
this.name = 'ConnectionError'
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export class StorageError extends OrbitError {
|
|
24
|
-
constructor(message: string, suggestion?: string) {
|
|
25
|
-
super(
|
|
26
|
-
message,
|
|
27
|
-
'STORAGE_ERROR',
|
|
28
|
-
suggestion ?? 'Check that your file exists and you have sufficient OG balance for gas fees.'
|
|
29
|
-
)
|
|
30
|
-
this.name = 'StorageError'
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
export class InferenceError extends OrbitError {
|
|
35
|
-
constructor(message: string, suggestion?: string) {
|
|
36
|
-
super(
|
|
37
|
-
message,
|
|
38
|
-
'INFERENCE_ERROR',
|
|
39
|
-
suggestion ?? 'Run orbit.listServices() to check available models and provider status.'
|
|
40
|
-
)
|
|
41
|
-
this.name = 'InferenceError'
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export class InsufficientBalanceError extends OrbitError {
|
|
46
|
-
constructor(
|
|
47
|
-
public readonly required: number,
|
|
48
|
-
public readonly available: number
|
|
49
|
-
) {
|
|
50
|
-
super(
|
|
51
|
-
`Insufficient balance: need ${required} OG but have ${available} OG`,
|
|
52
|
-
'INSUFFICIENT_BALANCE',
|
|
53
|
-
'Get testnet OG from the faucet: https://faucet.0g.ai'
|
|
54
|
-
)
|
|
55
|
-
this.name = 'InsufficientBalanceError'
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export class ProviderNotFoundError extends OrbitError {
|
|
60
|
-
constructor(message: string) {
|
|
61
|
-
super(
|
|
62
|
-
message,
|
|
63
|
-
'PROVIDER_NOT_FOUND',
|
|
64
|
-
'Run orbit.listServices() to see available models and their providers.'
|
|
65
|
-
)
|
|
66
|
-
this.name = 'ProviderNotFoundError'
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export class TimeoutError extends OrbitError {
|
|
71
|
-
constructor(message: string) {
|
|
72
|
-
super(
|
|
73
|
-
message,
|
|
74
|
-
'TIMEOUT',
|
|
75
|
-
'The request timed out. Try increasing the timeout option or check if the provider is responsive.'
|
|
76
|
-
)
|
|
77
|
-
this.name = 'TimeoutError'
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
export class FineTuningError extends OrbitError {
|
|
82
|
-
constructor(message: string, suggestion?: string) {
|
|
83
|
-
super(
|
|
84
|
-
message,
|
|
85
|
-
'FINE_TUNING_ERROR',
|
|
86
|
-
suggestion ?? 'Check model and provider availability with orbit.listModels() or orbit.listProviders().'
|
|
87
|
-
)
|
|
88
|
-
this.name = 'FineTuningError'
|
|
89
|
-
}
|
|
90
|
-
}
|
package/src/fine-tuning.test.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
2
|
-
import { NETWORKS } from './networks.js'
|
|
3
|
-
import { FineTuningError } from './errors.js'
|
|
4
|
-
|
|
5
|
-
// Hoist mocks so they can be referenced in vi.mock factories
|
|
6
|
-
const {
|
|
7
|
-
mockListModel,
|
|
8
|
-
mockListService,
|
|
9
|
-
mockListTask,
|
|
10
|
-
mockGetTask,
|
|
11
|
-
mockGetLog,
|
|
12
|
-
mockCreateTask,
|
|
13
|
-
mockAcknowledgeModel,
|
|
14
|
-
mockAcknowledgeProviderSigner,
|
|
15
|
-
mockStore,
|
|
16
|
-
} = vi.hoisted(() => ({
|
|
17
|
-
mockListModel: vi.fn(),
|
|
18
|
-
mockListService: vi.fn(),
|
|
19
|
-
mockListTask: vi.fn(),
|
|
20
|
-
mockGetTask: vi.fn(),
|
|
21
|
-
mockGetLog: vi.fn(),
|
|
22
|
-
mockCreateTask: vi.fn(),
|
|
23
|
-
mockAcknowledgeModel: vi.fn(),
|
|
24
|
-
mockAcknowledgeProviderSigner: vi.fn(),
|
|
25
|
-
mockStore: vi.fn(),
|
|
26
|
-
}))
|
|
27
|
-
|
|
28
|
-
vi.mock('@0glabs/0g-serving-broker', () => ({
|
|
29
|
-
createZGComputeNetworkBroker: vi.fn().mockResolvedValue({
|
|
30
|
-
fineTuning: {
|
|
31
|
-
listModel: mockListModel,
|
|
32
|
-
listService: mockListService,
|
|
33
|
-
listTask: mockListTask,
|
|
34
|
-
getTask: mockGetTask,
|
|
35
|
-
getLog: mockGetLog,
|
|
36
|
-
createTask: mockCreateTask,
|
|
37
|
-
acknowledgeModel: mockAcknowledgeModel,
|
|
38
|
-
acknowledgeProviderSigner: mockAcknowledgeProviderSigner,
|
|
39
|
-
},
|
|
40
|
-
ledger: {
|
|
41
|
-
getLedger: vi.fn(),
|
|
42
|
-
addLedger: vi.fn(),
|
|
43
|
-
},
|
|
44
|
-
inference: {},
|
|
45
|
-
}),
|
|
46
|
-
}))
|
|
47
|
-
|
|
48
|
-
vi.mock('./storage.js', () => ({
|
|
49
|
-
StorageClient: vi.fn().mockImplementation(() => ({
|
|
50
|
-
store: mockStore,
|
|
51
|
-
})),
|
|
52
|
-
}))
|
|
53
|
-
|
|
54
|
-
import { FineTuningClient } from './fine-tuning.js'
|
|
55
|
-
import { StorageClient } from './storage.js'
|
|
56
|
-
|
|
57
|
-
const mockWallet = {
|
|
58
|
-
address: '0x1234567890abcdef1234567890abcdef12345678',
|
|
59
|
-
privateKey: '0xdeadbeef',
|
|
60
|
-
} as any
|
|
61
|
-
const testNetwork = { ...NETWORKS.testnet }
|
|
62
|
-
const mockStorageClient = new StorageClient(testNetwork, mockWallet)
|
|
63
|
-
|
|
64
|
-
describe('FineTuningClient', () => {
|
|
65
|
-
let client: FineTuningClient
|
|
66
|
-
|
|
67
|
-
beforeEach(() => {
|
|
68
|
-
vi.clearAllMocks()
|
|
69
|
-
client = new FineTuningClient(testNetwork, mockWallet, mockStorageClient)
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
describe('lazy broker init', () => {
|
|
73
|
-
it('initializes broker on first call', async () => {
|
|
74
|
-
mockListModel.mockResolvedValueOnce([[], []])
|
|
75
|
-
|
|
76
|
-
await client.listModels()
|
|
77
|
-
const { createZGComputeNetworkBroker } = await import('@0glabs/0g-serving-broker')
|
|
78
|
-
expect(createZGComputeNetworkBroker).toHaveBeenCalledTimes(1)
|
|
79
|
-
})
|
|
80
|
-
|
|
81
|
-
it('reuses broker on subsequent calls', async () => {
|
|
82
|
-
mockListModel.mockResolvedValue([[], []])
|
|
83
|
-
|
|
84
|
-
await client.listModels()
|
|
85
|
-
await client.listModels()
|
|
86
|
-
const { createZGComputeNetworkBroker } = await import('@0glabs/0g-serving-broker')
|
|
87
|
-
expect(createZGComputeNetworkBroker).toHaveBeenCalledTimes(1)
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
it('throws FineTuningError on broker init failure', async () => {
|
|
91
|
-
const { createZGComputeNetworkBroker } = await import('@0glabs/0g-serving-broker')
|
|
92
|
-
;(createZGComputeNetworkBroker as any).mockRejectedValueOnce(
|
|
93
|
-
new Error('Network unreachable')
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
const freshClient = new FineTuningClient(testNetwork, mockWallet, mockStorageClient)
|
|
97
|
-
try {
|
|
98
|
-
await freshClient.listModels()
|
|
99
|
-
expect.unreachable('Should have thrown')
|
|
100
|
-
} catch (err) {
|
|
101
|
-
expect(err).toBeInstanceOf(FineTuningError)
|
|
102
|
-
expect((err as FineTuningError).message).toContain('Failed to initialize')
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
describe('uploadDataset', () => {
|
|
108
|
-
it('uploads a dataset and returns root + tx hash', async () => {
|
|
109
|
-
mockStore.mockResolvedValueOnce({
|
|
110
|
-
root: '0xdataset_root',
|
|
111
|
-
txHash: '0xtx_hash',
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
const result = await client.uploadDataset('/tmp/dataset.jsonl')
|
|
115
|
-
expect(result.root).toBe('0xdataset_root')
|
|
116
|
-
expect(result.txHash).toBe('0xtx_hash')
|
|
117
|
-
expect(mockStore).toHaveBeenCalledWith('/tmp/dataset.jsonl')
|
|
118
|
-
})
|
|
119
|
-
|
|
120
|
-
it('throws FineTuningError on file error', async () => {
|
|
121
|
-
mockStore.mockRejectedValueOnce(new Error('ENOENT: no such file'))
|
|
122
|
-
|
|
123
|
-
await expect(client.uploadDataset('/tmp/missing.jsonl')).rejects.toThrow(
|
|
124
|
-
FineTuningError
|
|
125
|
-
)
|
|
126
|
-
})
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
describe('createTask', () => {
|
|
130
|
-
it('creates a fine-tuning task', async () => {
|
|
131
|
-
mockAcknowledgeProviderSigner.mockResolvedValueOnce(undefined)
|
|
132
|
-
mockCreateTask.mockResolvedValueOnce('task-001')
|
|
133
|
-
|
|
134
|
-
const task = await client.createTask({
|
|
135
|
-
model: 'Qwen2.5-0.5B-Instruct',
|
|
136
|
-
dataset: '0xdataset_root',
|
|
137
|
-
providerAddress: '0xprovider',
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
expect(task.id).toBe('task-001')
|
|
141
|
-
expect(task.model).toBe('Qwen2.5-0.5B-Instruct')
|
|
142
|
-
expect(task.dataset).toBe('0xdataset_root')
|
|
143
|
-
expect(task.provider).toBe('0xprovider')
|
|
144
|
-
expect(task.status).toBe('init')
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
it('throws FineTuningError on invalid model', async () => {
|
|
148
|
-
mockAcknowledgeProviderSigner.mockResolvedValueOnce(undefined)
|
|
149
|
-
mockCreateTask.mockRejectedValueOnce(new Error('Model not found'))
|
|
150
|
-
|
|
151
|
-
await expect(
|
|
152
|
-
client.createTask({
|
|
153
|
-
model: 'nonexistent-model',
|
|
154
|
-
dataset: '0xdataset_root',
|
|
155
|
-
providerAddress: '0xprovider',
|
|
156
|
-
})
|
|
157
|
-
).rejects.toThrow(FineTuningError)
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
it('throws FineTuningError on missing provider', async () => {
|
|
161
|
-
mockAcknowledgeProviderSigner.mockRejectedValueOnce(
|
|
162
|
-
new Error('Provider not found')
|
|
163
|
-
)
|
|
164
|
-
|
|
165
|
-
await expect(
|
|
166
|
-
client.createTask({
|
|
167
|
-
model: 'Qwen2.5-0.5B-Instruct',
|
|
168
|
-
dataset: '0xdataset_root',
|
|
169
|
-
providerAddress: '0xbad_provider',
|
|
170
|
-
})
|
|
171
|
-
).rejects.toThrow(FineTuningError)
|
|
172
|
-
})
|
|
173
|
-
})
|
|
174
|
-
|
|
175
|
-
describe('getTask', () => {
|
|
176
|
-
it('returns a task by ID', async () => {
|
|
177
|
-
mockGetTask.mockResolvedValueOnce({
|
|
178
|
-
id: 'task-001',
|
|
179
|
-
preTrainedModelHash: '0xmodel',
|
|
180
|
-
datasetHash: '0xdata',
|
|
181
|
-
progress: 'Training',
|
|
182
|
-
createdAt: '2024-01-01',
|
|
183
|
-
updatedAt: '2024-01-02',
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
const task = await client.getTask('0xprovider', 'task-001')
|
|
187
|
-
expect(task.id).toBe('task-001')
|
|
188
|
-
expect(task.status).toBe('training')
|
|
189
|
-
expect(task.provider).toBe('0xprovider')
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
it('throws FineTuningError when task not found', async () => {
|
|
193
|
-
mockGetTask.mockRejectedValueOnce(new Error('No task found'))
|
|
194
|
-
|
|
195
|
-
await expect(
|
|
196
|
-
client.getTask('0xprovider', 'nonexistent')
|
|
197
|
-
).rejects.toThrow(FineTuningError)
|
|
198
|
-
})
|
|
199
|
-
})
|
|
200
|
-
|
|
201
|
-
describe('getTaskLog', () => {
|
|
202
|
-
it('returns the training log', async () => {
|
|
203
|
-
mockGetLog.mockResolvedValueOnce('Epoch 1/3: loss=0.5\nEpoch 2/3: loss=0.3')
|
|
204
|
-
|
|
205
|
-
const log = await client.getTaskLog('0xprovider', 'task-001')
|
|
206
|
-
expect(log).toContain('Epoch 1/3')
|
|
207
|
-
})
|
|
208
|
-
})
|
|
209
|
-
|
|
210
|
-
describe('listTasks', () => {
|
|
211
|
-
it('returns all tasks for a provider', async () => {
|
|
212
|
-
mockListTask.mockResolvedValueOnce([
|
|
213
|
-
{ id: 'task-001', preTrainedModelHash: '0xm1', datasetHash: '0xd1', progress: 'Finished' },
|
|
214
|
-
{ id: 'task-002', preTrainedModelHash: '0xm2', datasetHash: '0xd2', progress: 'Training' },
|
|
215
|
-
])
|
|
216
|
-
|
|
217
|
-
const tasks = await client.listTasks('0xprovider')
|
|
218
|
-
expect(tasks).toHaveLength(2)
|
|
219
|
-
expect(tasks[0].status).toBe('finished')
|
|
220
|
-
expect(tasks[1].status).toBe('training')
|
|
221
|
-
})
|
|
222
|
-
})
|
|
223
|
-
|
|
224
|
-
describe('downloadModel', () => {
|
|
225
|
-
it('downloads a model via acknowledgeModel', async () => {
|
|
226
|
-
mockAcknowledgeModel.mockResolvedValueOnce(undefined)
|
|
227
|
-
|
|
228
|
-
await expect(
|
|
229
|
-
client.downloadModel('0xprovider', 'task-001', '/tmp/model')
|
|
230
|
-
).resolves.toBeUndefined()
|
|
231
|
-
|
|
232
|
-
expect(mockAcknowledgeModel).toHaveBeenCalledWith(
|
|
233
|
-
'0xprovider',
|
|
234
|
-
'task-001',
|
|
235
|
-
'/tmp/model'
|
|
236
|
-
)
|
|
237
|
-
})
|
|
238
|
-
|
|
239
|
-
it('throws FineTuningError when task not ready', async () => {
|
|
240
|
-
mockAcknowledgeModel.mockRejectedValueOnce(
|
|
241
|
-
new Error('No deliverable found')
|
|
242
|
-
)
|
|
243
|
-
|
|
244
|
-
await expect(
|
|
245
|
-
client.downloadModel('0xprovider', 'task-001', '/tmp/model')
|
|
246
|
-
).rejects.toThrow(FineTuningError)
|
|
247
|
-
})
|
|
248
|
-
})
|
|
249
|
-
|
|
250
|
-
describe('listModels', () => {
|
|
251
|
-
it('returns combined standard and customized models', async () => {
|
|
252
|
-
mockListModel.mockResolvedValueOnce([
|
|
253
|
-
[['Qwen2.5-0.5B-Instruct', { turbo: '0xhash', description: 'Qwen model' }]],
|
|
254
|
-
[['my-custom', { description: 'Custom fine-tuned', provider: '0xp1' }]],
|
|
255
|
-
])
|
|
256
|
-
|
|
257
|
-
const models = await client.listModels()
|
|
258
|
-
expect(models).toHaveLength(2)
|
|
259
|
-
expect(models[0].name).toBe('Qwen2.5-0.5B-Instruct')
|
|
260
|
-
expect(models[1].name).toBe('my-custom')
|
|
261
|
-
expect(models[1].config.provider).toBe('0xp1')
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
it('returns empty array when no models', async () => {
|
|
265
|
-
mockListModel.mockResolvedValueOnce([[], []])
|
|
266
|
-
|
|
267
|
-
const models = await client.listModels()
|
|
268
|
-
expect(models).toHaveLength(0)
|
|
269
|
-
})
|
|
270
|
-
})
|
|
271
|
-
|
|
272
|
-
describe('listProviders', () => {
|
|
273
|
-
it('returns fine-tuning providers', async () => {
|
|
274
|
-
mockListService.mockResolvedValueOnce([
|
|
275
|
-
{ provider: '0xprovider1', url: 'https://p1.example.com', models: ['model1'] },
|
|
276
|
-
{ provider: '0xprovider2', url: 'https://p2.example.com', models: [] },
|
|
277
|
-
])
|
|
278
|
-
|
|
279
|
-
const providers = await client.listProviders()
|
|
280
|
-
expect(providers).toHaveLength(2)
|
|
281
|
-
expect(providers[0].address).toBe('0xprovider1')
|
|
282
|
-
expect(providers[0].url).toBe('https://p1.example.com')
|
|
283
|
-
expect(providers[0].models).toEqual(['model1'])
|
|
284
|
-
})
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
describe('error suggestions', () => {
|
|
288
|
-
it('FineTuningError includes default suggestion', () => {
|
|
289
|
-
const err = new FineTuningError('Something failed')
|
|
290
|
-
expect(err.code).toBe('FINE_TUNING_ERROR')
|
|
291
|
-
expect(err.suggestion).toContain('listModels')
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
it('FineTuningError allows custom suggestion', () => {
|
|
295
|
-
const err = new FineTuningError('Oops', 'Try this instead')
|
|
296
|
-
expect(err.suggestion).toBe('Try this instead')
|
|
297
|
-
})
|
|
298
|
-
})
|
|
299
|
-
})
|