@stacknet/stacks 0.1.2 → 0.2.2
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/README.md +136 -0
- package/dist/{billing-BqscteyZ.d.cts → billing-cj0eSVrp.d.cts} +61 -1
- package/dist/{billing-BqscteyZ.d.ts → billing-cj0eSVrp.d.ts} +61 -1
- package/dist/clients/index.cjs +4 -4
- package/dist/clients/index.d.cts +27 -1
- package/dist/clients/index.d.ts +27 -1
- package/dist/clients/index.js +4 -4
- package/dist/{index-DVzKiF_0.d.cts → index-B_dUFmAg.d.cts} +31 -6
- package/dist/{index-DVzKiF_0.d.ts → index-B_dUFmAg.d.ts} +31 -6
- package/dist/index.cjs +12 -16
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +12 -16
- package/dist/proxy/index.cjs +2 -2
- package/dist/proxy/index.d.cts +1 -1
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.js +2 -2
- package/dist/streaming/index.cjs +8 -12
- package/dist/streaming/index.js +8 -12
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +15 -13
- package/src/clients/agents.ts +0 -233
- package/src/clients/billing.ts +0 -197
- package/src/clients/coder.ts +0 -655
- package/src/clients/files.ts +0 -86
- package/src/clients/index.ts +0 -93
- package/src/clients/magma.ts +0 -299
- package/src/clients/mcp.ts +0 -208
- package/src/clients/network.ts +0 -118
- package/src/clients/points.ts +0 -403
- package/src/clients/skills.ts +0 -236
- package/src/clients/social.ts +0 -286
- package/src/clients/stack-management.ts +0 -279
- package/src/clients/task-network.ts +0 -303
- package/src/clients/user.ts +0 -84
- package/src/clients/widgets.ts +0 -171
- package/src/index.ts +0 -387
- package/src/managers/index.ts +0 -10
- package/src/managers/task-manager.ts +0 -310
- package/src/proxy/forwarder.ts +0 -146
- package/src/proxy/index.ts +0 -32
- package/src/proxy/route-handlers.ts +0 -950
- package/src/streaming/component-stream.ts +0 -319
- package/src/streaming/index.ts +0 -21
- package/src/streaming/sse.ts +0 -241
- package/src/types/agent.ts +0 -106
- package/src/types/billing.ts +0 -121
- package/src/types/chat.ts +0 -58
- package/src/types/coder.ts +0 -345
- package/src/types/credential.ts +0 -111
- package/src/types/file.ts +0 -15
- package/src/types/imagination.ts +0 -50
- package/src/types/index.ts +0 -20
- package/src/types/mcp.ts +0 -35
- package/src/types/network.ts +0 -97
- package/src/types/points.ts +0 -250
- package/src/types/skill.ts +0 -107
- package/src/types/social.ts +0 -109
- package/src/types/stack.ts +0 -269
- package/src/types/task.ts +0 -41
- package/src/types/user.ts +0 -29
- package/src/types/widget.ts +0 -57
- package/src/utils/constants.ts +0 -26
- package/src/utils/errors.ts +0 -169
- package/src/utils/helpers.ts +0 -85
- package/src/utils/index.ts +0 -7
package/src/clients/files.ts
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Files Client
|
|
3
|
-
* Client for file upload operations
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { DEFAULT_TASK_NETWORK_URL } from '../utils/constants';
|
|
7
|
-
import { StacksSDKError } from '../utils/errors';
|
|
8
|
-
import type {
|
|
9
|
-
FileUploadResponse,
|
|
10
|
-
FilesClientConfig,
|
|
11
|
-
} from '../types/file';
|
|
12
|
-
|
|
13
|
-
export type { FilesClientConfig } from '../types/file';
|
|
14
|
-
|
|
15
|
-
export class FilesClient {
|
|
16
|
-
private baseUrl: string;
|
|
17
|
-
|
|
18
|
-
constructor(config: FilesClientConfig = {}) {
|
|
19
|
-
this.baseUrl = config.baseUrl || DEFAULT_TASK_NETWORK_URL;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
private get filesUrl(): string {
|
|
23
|
-
return `${this.baseUrl}/files`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Upload a file
|
|
28
|
-
*/
|
|
29
|
-
async upload(file: File | Blob, filename?: string): Promise<FileUploadResponse> {
|
|
30
|
-
const formData = new FormData();
|
|
31
|
-
formData.append('file', file, filename);
|
|
32
|
-
|
|
33
|
-
const response = await fetch(`${this.filesUrl}/upload`, {
|
|
34
|
-
method: 'POST',
|
|
35
|
-
body: formData,
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
if (!response.ok) {
|
|
39
|
-
throw new StacksSDKError(
|
|
40
|
-
'bad_request:api',
|
|
41
|
-
`Failed to upload file: ${response.statusText}`
|
|
42
|
-
);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
return response.json();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Upload a file from URL
|
|
50
|
-
*/
|
|
51
|
-
async uploadFromUrl(url: string): Promise<FileUploadResponse> {
|
|
52
|
-
const response = await fetch(`${this.filesUrl}/upload-url`, {
|
|
53
|
-
method: 'POST',
|
|
54
|
-
headers: { 'Content-Type': 'application/json' },
|
|
55
|
-
body: JSON.stringify({ url }),
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
if (!response.ok) {
|
|
59
|
-
throw new StacksSDKError(
|
|
60
|
-
'bad_request:api',
|
|
61
|
-
`Failed to upload file from URL: ${response.statusText}`
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return response.json();
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Get file URL by CID
|
|
70
|
-
*/
|
|
71
|
-
getFileUrl(cid: string): string {
|
|
72
|
-
return `${this.filesUrl}/${cid}`;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Create a FilesClient instance
|
|
78
|
-
*/
|
|
79
|
-
export function createFilesClient(config: FilesClientConfig = {}): FilesClient {
|
|
80
|
-
return new FilesClient(config);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* Default files client instance
|
|
85
|
-
*/
|
|
86
|
-
export const filesClient = createFilesClient();
|
package/src/clients/index.ts
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @stacknet/stacks - Clients
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
export {
|
|
6
|
-
TaskNetworkClient,
|
|
7
|
-
createTaskNetworkClient,
|
|
8
|
-
taskNetworkClient,
|
|
9
|
-
type TaskNetworkConfig,
|
|
10
|
-
} from './task-network';
|
|
11
|
-
|
|
12
|
-
export {
|
|
13
|
-
MagmaClient,
|
|
14
|
-
createMagmaClient,
|
|
15
|
-
magmaClient,
|
|
16
|
-
type MagmaClientConfig,
|
|
17
|
-
} from './magma';
|
|
18
|
-
|
|
19
|
-
export {
|
|
20
|
-
MCPClient,
|
|
21
|
-
createMCPClient,
|
|
22
|
-
mcpClient,
|
|
23
|
-
} from './mcp';
|
|
24
|
-
|
|
25
|
-
export {
|
|
26
|
-
SocialClient,
|
|
27
|
-
createSocialClient,
|
|
28
|
-
socialClient,
|
|
29
|
-
type SocialClientConfig,
|
|
30
|
-
} from './social';
|
|
31
|
-
|
|
32
|
-
export {
|
|
33
|
-
AgentsClient,
|
|
34
|
-
createAgentsClient,
|
|
35
|
-
agentsClient,
|
|
36
|
-
type AgentsClientConfig,
|
|
37
|
-
} from './agents';
|
|
38
|
-
|
|
39
|
-
export {
|
|
40
|
-
WidgetsClient,
|
|
41
|
-
createWidgetsClient,
|
|
42
|
-
widgetsClient,
|
|
43
|
-
type WidgetsClientConfig,
|
|
44
|
-
} from './widgets';
|
|
45
|
-
|
|
46
|
-
export {
|
|
47
|
-
UserClient,
|
|
48
|
-
createUserClient,
|
|
49
|
-
userClient,
|
|
50
|
-
type UserClientConfig,
|
|
51
|
-
} from './user';
|
|
52
|
-
|
|
53
|
-
export {
|
|
54
|
-
FilesClient,
|
|
55
|
-
createFilesClient,
|
|
56
|
-
filesClient,
|
|
57
|
-
type FilesClientConfig,
|
|
58
|
-
} from './files';
|
|
59
|
-
|
|
60
|
-
export {
|
|
61
|
-
SkillsClient,
|
|
62
|
-
createSkillsClient,
|
|
63
|
-
skillsClient,
|
|
64
|
-
type SkillsClientConfig,
|
|
65
|
-
} from './skills';
|
|
66
|
-
|
|
67
|
-
export {
|
|
68
|
-
PointsClient,
|
|
69
|
-
createPointsClient,
|
|
70
|
-
pointsClient,
|
|
71
|
-
type PointsClientConfig,
|
|
72
|
-
} from './points';
|
|
73
|
-
|
|
74
|
-
export {
|
|
75
|
-
StackManagementClient,
|
|
76
|
-
createStackManagementClient,
|
|
77
|
-
stackManagementClient,
|
|
78
|
-
type StackManagementClientConfig,
|
|
79
|
-
} from './stack-management';
|
|
80
|
-
|
|
81
|
-
export {
|
|
82
|
-
NetworkClient,
|
|
83
|
-
createNetworkClient,
|
|
84
|
-
networkClient,
|
|
85
|
-
type NetworkClientConfig,
|
|
86
|
-
} from './network';
|
|
87
|
-
|
|
88
|
-
export {
|
|
89
|
-
BillingClient,
|
|
90
|
-
createBillingClient,
|
|
91
|
-
billingClient,
|
|
92
|
-
type BillingClientConfig,
|
|
93
|
-
} from './billing';
|
package/src/clients/magma.ts
DELETED
|
@@ -1,299 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MagmaClient - File storage and imagination management
|
|
3
|
-
*
|
|
4
|
-
* Interfaces with the MetaChain P2P network for distributed file storage
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { MagmaFile, ImaginationMetadata, WorkflowData } from '../types';
|
|
8
|
-
import { DEFAULT_MAGMA_RPC_URL, DEFAULT_TASK_NETWORK_URL } from '../utils/constants';
|
|
9
|
-
import { generateCID } from '../utils/helpers';
|
|
10
|
-
|
|
11
|
-
export interface MagmaClientConfig {
|
|
12
|
-
baseUrl?: string;
|
|
13
|
-
localServerUrl?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export class MagmaClient {
|
|
17
|
-
private baseUrl: string;
|
|
18
|
-
private localServerUrl: string;
|
|
19
|
-
|
|
20
|
-
constructor(config: MagmaClientConfig = {}) {
|
|
21
|
-
this.baseUrl = config.baseUrl || DEFAULT_MAGMA_RPC_URL;
|
|
22
|
-
this.localServerUrl = config.localServerUrl || DEFAULT_TASK_NETWORK_URL;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Upload a file and get its CID
|
|
27
|
-
*/
|
|
28
|
-
async uploadFile(file: File): Promise<MagmaFile> {
|
|
29
|
-
const arrayBuffer = await file.arrayBuffer();
|
|
30
|
-
const cid = await generateCID(arrayBuffer);
|
|
31
|
-
|
|
32
|
-
// Convert to base64 for storage
|
|
33
|
-
const base64Data = this.arrayBufferToBase64(arrayBuffer);
|
|
34
|
-
|
|
35
|
-
// Store in localStorage (browser) or return for server storage
|
|
36
|
-
if (typeof localStorage !== 'undefined') {
|
|
37
|
-
localStorage.setItem(
|
|
38
|
-
`file:${cid}`,
|
|
39
|
-
JSON.stringify({
|
|
40
|
-
cid,
|
|
41
|
-
name: file.name,
|
|
42
|
-
type: file.type,
|
|
43
|
-
size: file.size,
|
|
44
|
-
data: base64Data,
|
|
45
|
-
})
|
|
46
|
-
);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
cid,
|
|
51
|
-
name: file.name,
|
|
52
|
-
size: file.size,
|
|
53
|
-
type: file.type,
|
|
54
|
-
url: `data:${file.type};base64,${base64Data}`,
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Upload text content and get its CID
|
|
60
|
-
*/
|
|
61
|
-
async uploadText(text: string, name: string): Promise<MagmaFile> {
|
|
62
|
-
const blob = new Blob([text], { type: 'text/plain' });
|
|
63
|
-
const file = new File([blob], name, { type: 'text/plain' });
|
|
64
|
-
return this.uploadFile(file);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Store imagination metadata in P2P network
|
|
69
|
-
*/
|
|
70
|
-
async storeImagination(
|
|
71
|
-
imagination: ImaginationMetadata & { is_public?: boolean }
|
|
72
|
-
): Promise<string> {
|
|
73
|
-
const creatorMid = imagination.createdBy || 'anonymous';
|
|
74
|
-
|
|
75
|
-
// Check if imagination already exists
|
|
76
|
-
const existingResponse = await fetch(
|
|
77
|
-
`${this.localServerUrl}/imaginations/${imagination.id}`
|
|
78
|
-
);
|
|
79
|
-
const isUpdate = existingResponse.ok;
|
|
80
|
-
|
|
81
|
-
const payload = {
|
|
82
|
-
id: imagination.id,
|
|
83
|
-
title: imagination.title,
|
|
84
|
-
sources: imagination.sources,
|
|
85
|
-
summary: imagination.summary,
|
|
86
|
-
character: imagination.character,
|
|
87
|
-
workflow: imagination.workflow,
|
|
88
|
-
is_public: imagination.is_public || false,
|
|
89
|
-
creator_mid: creatorMid,
|
|
90
|
-
};
|
|
91
|
-
|
|
92
|
-
if (isUpdate) {
|
|
93
|
-
const response = await fetch(
|
|
94
|
-
`${this.localServerUrl}/imaginations/${imagination.id}`,
|
|
95
|
-
{
|
|
96
|
-
method: 'PUT',
|
|
97
|
-
headers: { 'Content-Type': 'application/json' },
|
|
98
|
-
body: JSON.stringify(payload),
|
|
99
|
-
}
|
|
100
|
-
);
|
|
101
|
-
|
|
102
|
-
if (!response.ok) {
|
|
103
|
-
throw new Error(`Failed to update imagination: ${response.statusText}`);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Cache locally
|
|
107
|
-
if (typeof localStorage !== 'undefined') {
|
|
108
|
-
localStorage.setItem(`imagination:${imagination.id}`, imagination.id);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return imagination.id;
|
|
112
|
-
} else {
|
|
113
|
-
const response = await fetch(`${this.localServerUrl}/imaginations`, {
|
|
114
|
-
method: 'POST',
|
|
115
|
-
headers: { 'Content-Type': 'application/json' },
|
|
116
|
-
body: JSON.stringify(payload),
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
if (!response.ok) {
|
|
120
|
-
throw new Error(`Failed to store imagination: ${response.statusText}`);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
const result = await response.json();
|
|
124
|
-
const id = result.imagination?.id || imagination.id;
|
|
125
|
-
|
|
126
|
-
// Cache locally
|
|
127
|
-
if (typeof localStorage !== 'undefined') {
|
|
128
|
-
localStorage.setItem(`imagination:${id}`, id);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return id;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Retrieve imagination from P2P network by ID
|
|
137
|
-
*/
|
|
138
|
-
async getImagination(id: string): Promise<ImaginationMetadata | null> {
|
|
139
|
-
try {
|
|
140
|
-
const response = await fetch(`${this.localServerUrl}/imaginations/${id}`);
|
|
141
|
-
if (!response.ok) {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
const result = await response.json();
|
|
146
|
-
if (!result.imagination) {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return {
|
|
151
|
-
id: result.imagination.id,
|
|
152
|
-
title: result.imagination.title,
|
|
153
|
-
createdAt: new Date(result.imagination.created_at).toISOString(),
|
|
154
|
-
createdBy: result.imagination.creator_mid,
|
|
155
|
-
sources: result.imagination.sources,
|
|
156
|
-
summary: result.imagination.summary,
|
|
157
|
-
character: result.imagination.character,
|
|
158
|
-
workflow: result.imagination.workflow,
|
|
159
|
-
is_public: result.imagination.is_public,
|
|
160
|
-
};
|
|
161
|
-
} catch (error) {
|
|
162
|
-
console.error('Failed to retrieve imagination:', error);
|
|
163
|
-
return null;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Get imagination by CID
|
|
169
|
-
*/
|
|
170
|
-
async getImaginationByCID(cid: string): Promise<ImaginationMetadata | null> {
|
|
171
|
-
try {
|
|
172
|
-
const response = await fetch(`${this.baseUrl}/files/${cid}`);
|
|
173
|
-
if (!response.ok) {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const imagination: ImaginationMetadata = await response.json();
|
|
178
|
-
|
|
179
|
-
// Cache locally
|
|
180
|
-
if (typeof localStorage !== 'undefined') {
|
|
181
|
-
localStorage.setItem(`imagination:${imagination.id}`, cid);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
return imagination;
|
|
185
|
-
} catch (error) {
|
|
186
|
-
console.error('Failed to retrieve imagination by CID:', error);
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* List all imaginations for a user
|
|
193
|
-
*/
|
|
194
|
-
async listImaginations(creatorMid?: string): Promise<ImaginationMetadata[]> {
|
|
195
|
-
try {
|
|
196
|
-
const userMid = creatorMid || 'anonymous';
|
|
197
|
-
const response = await fetch(
|
|
198
|
-
`${this.localServerUrl}/imaginations?creator_mid=${encodeURIComponent(userMid)}`
|
|
199
|
-
);
|
|
200
|
-
|
|
201
|
-
if (!response.ok) {
|
|
202
|
-
console.warn('Failed to fetch imaginations from P2P, falling back to localStorage');
|
|
203
|
-
return this.listImaginationsFromLocalStorage();
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
const result = await response.json();
|
|
207
|
-
|
|
208
|
-
const imaginations: ImaginationMetadata[] = result.imaginations.map(
|
|
209
|
-
(img: Record<string, unknown>) => ({
|
|
210
|
-
id: img.id as string,
|
|
211
|
-
title: img.title as string,
|
|
212
|
-
createdAt: new Date(img.created_at as string).toISOString(),
|
|
213
|
-
createdBy: img.creator_mid as string,
|
|
214
|
-
sources: img.sources as ImaginationMetadata['sources'],
|
|
215
|
-
summary: img.summary as string | undefined,
|
|
216
|
-
character: img.character as ImaginationMetadata['character'],
|
|
217
|
-
workflow: img.workflow as WorkflowData | undefined,
|
|
218
|
-
is_public: img.is_public as boolean | undefined,
|
|
219
|
-
})
|
|
220
|
-
);
|
|
221
|
-
|
|
222
|
-
// Cache locally
|
|
223
|
-
if (typeof localStorage !== 'undefined') {
|
|
224
|
-
imaginations.forEach((img) => {
|
|
225
|
-
localStorage.setItem(`imagination:${img.id}`, img.id);
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
return imaginations;
|
|
230
|
-
} catch (error) {
|
|
231
|
-
console.error('Failed to list imaginations:', error);
|
|
232
|
-
return this.listImaginationsFromLocalStorage();
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Fallback method to list imaginations from localStorage
|
|
238
|
-
*/
|
|
239
|
-
private async listImaginationsFromLocalStorage(): Promise<ImaginationMetadata[]> {
|
|
240
|
-
if (typeof localStorage === 'undefined') {
|
|
241
|
-
return [];
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
const imaginations: ImaginationMetadata[] = [];
|
|
245
|
-
|
|
246
|
-
for (let i = 0; i < localStorage.length; i++) {
|
|
247
|
-
const key = localStorage.key(i);
|
|
248
|
-
if (key && key.startsWith('imagination:')) {
|
|
249
|
-
const id = key.replace('imagination:', '');
|
|
250
|
-
const imagination = await this.getImagination(id);
|
|
251
|
-
if (imagination) {
|
|
252
|
-
imaginations.push(imagination);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return imaginations;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Retrieve file from Magma network
|
|
262
|
-
*/
|
|
263
|
-
async getFile(cid: string): Promise<Blob | null> {
|
|
264
|
-
try {
|
|
265
|
-
const response = await fetch(`${this.baseUrl}/files/${cid}`);
|
|
266
|
-
if (!response.ok) {
|
|
267
|
-
return null;
|
|
268
|
-
}
|
|
269
|
-
return await response.blob();
|
|
270
|
-
} catch (error) {
|
|
271
|
-
console.error('Failed to retrieve file:', error);
|
|
272
|
-
return null;
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/**
|
|
277
|
-
* Helper to convert ArrayBuffer to base64
|
|
278
|
-
*/
|
|
279
|
-
private arrayBufferToBase64(buffer: ArrayBuffer): string {
|
|
280
|
-
const bytes = new Uint8Array(buffer);
|
|
281
|
-
let binary = '';
|
|
282
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
283
|
-
binary += String.fromCharCode(bytes[i]);
|
|
284
|
-
}
|
|
285
|
-
return btoa(binary);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Factory function to create a client
|
|
291
|
-
*/
|
|
292
|
-
export function createMagmaClient(config?: MagmaClientConfig): MagmaClient {
|
|
293
|
-
return new MagmaClient(config);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/**
|
|
297
|
-
* Default singleton instance
|
|
298
|
-
*/
|
|
299
|
-
export const magmaClient = createMagmaClient();
|
package/src/clients/mcp.ts
DELETED
|
@@ -1,208 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCPClient - Model Context Protocol client
|
|
3
|
-
*
|
|
4
|
-
* Simple MCP client for communicating with magmanode MCP services
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { MCPSession, MCPSessionConfig, MCPToolResult } from '../types';
|
|
8
|
-
|
|
9
|
-
export class MCPClient {
|
|
10
|
-
private baseUrl: string;
|
|
11
|
-
private timeout: number;
|
|
12
|
-
private sessions: Map<string, MCPSession> = new Map();
|
|
13
|
-
|
|
14
|
-
constructor(config: MCPSessionConfig = {}) {
|
|
15
|
-
this.baseUrl = config.baseUrl || 'http://localhost:3006';
|
|
16
|
-
this.timeout = config.timeout || 30000;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Create a new MCP session
|
|
21
|
-
*/
|
|
22
|
-
async createSession(agentId: string = 'default'): Promise<MCPSession> {
|
|
23
|
-
const sessionId = `session_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
const session: MCPSession = {
|
|
27
|
-
id: sessionId,
|
|
28
|
-
agentId,
|
|
29
|
-
status: 'active',
|
|
30
|
-
createdAt: new Date(),
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
this.sessions.set(sessionId, session);
|
|
34
|
-
|
|
35
|
-
// Try to create session on server
|
|
36
|
-
try {
|
|
37
|
-
await fetch(`${this.baseUrl}/mcp/sessions`, {
|
|
38
|
-
method: 'POST',
|
|
39
|
-
headers: { 'Content-Type': 'application/json' },
|
|
40
|
-
body: JSON.stringify({
|
|
41
|
-
sessionId,
|
|
42
|
-
agentId,
|
|
43
|
-
clientInfo: {
|
|
44
|
-
name: 'stacknet-sdk',
|
|
45
|
-
version: '0.1.0',
|
|
46
|
-
},
|
|
47
|
-
}),
|
|
48
|
-
});
|
|
49
|
-
} catch {
|
|
50
|
-
// Server may not be available, continue with local session
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return session;
|
|
54
|
-
} catch (error) {
|
|
55
|
-
throw new Error(`Failed to create MCP session: ${error}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Get session by ID
|
|
61
|
-
*/
|
|
62
|
-
getSession(sessionId: string): MCPSession | undefined {
|
|
63
|
-
return this.sessions.get(sessionId);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Close a session
|
|
68
|
-
*/
|
|
69
|
-
async closeSession(sessionId: string): Promise<void> {
|
|
70
|
-
const session = this.sessions.get(sessionId);
|
|
71
|
-
if (session) {
|
|
72
|
-
session.status = 'closed';
|
|
73
|
-
|
|
74
|
-
try {
|
|
75
|
-
await fetch(`${this.baseUrl}/mcp/sessions/${sessionId}`, {
|
|
76
|
-
method: 'DELETE',
|
|
77
|
-
});
|
|
78
|
-
} catch {
|
|
79
|
-
// Ignore errors on close
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
this.sessions.delete(sessionId);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Send a message to an MCP session
|
|
88
|
-
*/
|
|
89
|
-
async sendMessage(sessionId: string, message: string): Promise<unknown> {
|
|
90
|
-
const session = this.sessions.get(sessionId);
|
|
91
|
-
if (!session || session.status !== 'active') {
|
|
92
|
-
throw new Error('Invalid or inactive session');
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
try {
|
|
96
|
-
const response = await fetch(
|
|
97
|
-
`${this.baseUrl}/mcp/sessions/${sessionId}/messages`,
|
|
98
|
-
{
|
|
99
|
-
method: 'POST',
|
|
100
|
-
headers: { 'Content-Type': 'application/json' },
|
|
101
|
-
body: JSON.stringify({
|
|
102
|
-
messages: [
|
|
103
|
-
{
|
|
104
|
-
role: 'user',
|
|
105
|
-
content: { type: 'text', text: message },
|
|
106
|
-
},
|
|
107
|
-
],
|
|
108
|
-
}),
|
|
109
|
-
}
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
if (!response.ok) {
|
|
113
|
-
throw new Error(`MCP request failed: ${response.statusText}`);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return response.json();
|
|
117
|
-
} catch (error) {
|
|
118
|
-
throw new Error(`Failed to send message: ${error}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Call an MCP tool
|
|
124
|
-
*/
|
|
125
|
-
async callTool(
|
|
126
|
-
sessionId: string,
|
|
127
|
-
toolName: string,
|
|
128
|
-
args: Record<string, unknown> = {}
|
|
129
|
-
): Promise<MCPToolResult> {
|
|
130
|
-
const session = this.sessions.get(sessionId);
|
|
131
|
-
if (!session || session.status !== 'active') {
|
|
132
|
-
throw new Error('Invalid or inactive session');
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
try {
|
|
136
|
-
const response = await fetch(
|
|
137
|
-
`${this.baseUrl}/mcp/sessions/${sessionId}/tools/${toolName}`,
|
|
138
|
-
{
|
|
139
|
-
method: 'POST',
|
|
140
|
-
headers: { 'Content-Type': 'application/json' },
|
|
141
|
-
body: JSON.stringify(args),
|
|
142
|
-
}
|
|
143
|
-
);
|
|
144
|
-
|
|
145
|
-
if (!response.ok) {
|
|
146
|
-
throw new Error(`Tool call failed: ${response.statusText}`);
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return response.json();
|
|
150
|
-
} catch (error) {
|
|
151
|
-
throw new Error(`Failed to call tool: ${error}`);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* List available tools for a session
|
|
157
|
-
*/
|
|
158
|
-
async listTools(sessionId: string): Promise<string[]> {
|
|
159
|
-
const session = this.sessions.get(sessionId);
|
|
160
|
-
if (!session || session.status !== 'active') {
|
|
161
|
-
throw new Error('Invalid or inactive session');
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
try {
|
|
165
|
-
const response = await fetch(
|
|
166
|
-
`${this.baseUrl}/mcp/sessions/${sessionId}/tools`
|
|
167
|
-
);
|
|
168
|
-
|
|
169
|
-
if (!response.ok) {
|
|
170
|
-
return [];
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const data = await response.json();
|
|
174
|
-
return data.tools || [];
|
|
175
|
-
} catch {
|
|
176
|
-
return [];
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Get all active sessions
|
|
182
|
-
*/
|
|
183
|
-
getActiveSessions(): MCPSession[] {
|
|
184
|
-
return Array.from(this.sessions.values()).filter(
|
|
185
|
-
(s) => s.status === 'active'
|
|
186
|
-
);
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
/**
|
|
190
|
-
* Close all sessions
|
|
191
|
-
*/
|
|
192
|
-
async closeAllSessions(): Promise<void> {
|
|
193
|
-
const sessions = Array.from(this.sessions.keys());
|
|
194
|
-
await Promise.all(sessions.map((id) => this.closeSession(id)));
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Factory function to create a client
|
|
200
|
-
*/
|
|
201
|
-
export function createMCPClient(config?: MCPSessionConfig): MCPClient {
|
|
202
|
-
return new MCPClient(config);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Default singleton instance
|
|
207
|
-
*/
|
|
208
|
-
export const mcpClient = createMCPClient();
|