@blaxel/core 0.2.6 → 0.2.7-preview.7
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 +116 -0
- package/dist/authentication/clientcredentials.d.ts +2 -0
- package/dist/authentication/clientcredentials.js +16 -1
- package/dist/jobs/index.d.ts +2 -0
- package/dist/jobs/index.js +2 -0
- package/dist/jobs/jobs.d.ts +10 -8
- package/dist/jobs/jobs.js +80 -40
- package/dist/jobs/start.d.ts +1 -0
- package/dist/jobs/start.js +83 -0
- package/dist/jobs/types.d.ts +3 -0
- package/dist/jobs/types.js +2 -0
- package/dist/telemetry/telemetry.d.ts +4 -1
- package/dist/telemetry/telemetry.js +9 -2
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# Blaxel Typescript SDK
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="https://blaxel.ai/logo.png" alt="Blaxel"/>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
**Blaxel is a computing platform for AI agent builders, with all the services and infrastructure to build and deploy agents efficiently.** This repository contains the TypeScript SDK to create and manage resources on Blaxel.
|
|
8
|
+
|
|
9
|
+
## Table of Contents
|
|
10
|
+
|
|
11
|
+
- [Installation](#installation)
|
|
12
|
+
- [Optional libraries](#optional-libraries)
|
|
13
|
+
- [Authentication](#authentication)
|
|
14
|
+
- [Features](#features)
|
|
15
|
+
- [Quickstart](#quickstart)
|
|
16
|
+
- [Contributing](#contributing)
|
|
17
|
+
- [License](#license)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Install Blaxel core SDK, which lets you manage Blaxel resources.
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
## npm
|
|
27
|
+
npm install @blaxel/core
|
|
28
|
+
|
|
29
|
+
## pnpm
|
|
30
|
+
pnpm i @blaxel/core
|
|
31
|
+
|
|
32
|
+
## yarn
|
|
33
|
+
yarn add @blaxel/core
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
### Optional libraries
|
|
38
|
+
Blaxel SDK is split between multiple packages. *core* is the minimal package to connect to Blaxel. You can find other packages to help you integrate with your favorite AI framework, or set up telemetry.
|
|
39
|
+
|
|
40
|
+
- [@blaxel/telemetry](@blaxel/telemetry/README.md)
|
|
41
|
+
- [@blaxel/vercel](@blaxel/vercel/README.md)
|
|
42
|
+
- [@blaxel/llamaindex](@blaxel/llamaindex/README.md)
|
|
43
|
+
- [@blaxel/langgraph](@blaxel/langgraph/README.md)
|
|
44
|
+
- [@blaxel/mastra](@blaxel/mastra/README.md)
|
|
45
|
+
|
|
46
|
+
Instrumentation happens automatically when workloads run on Blaxel. To enable telemetry, simply require the SDK in your project's entry point.
|
|
47
|
+
```ts
|
|
48
|
+
import "@blaxel/telemetry";
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
### Authentication
|
|
53
|
+
|
|
54
|
+
The Blaxel SDK authenticates with your workspace using credentials from these sources, in priority order:
|
|
55
|
+
1. When running on Blaxel, authentication is handled automatically
|
|
56
|
+
2. Variables in your .env file (`BL_WORKSPACE` and `BL_API_KEY`, or see [this page](https://docs.blaxel.ai/Agents/Variables-and-secrets) for other authentication options).
|
|
57
|
+
3. Environment variables from your machine
|
|
58
|
+
4. Configuration file created locally when you log in through Blaxel CLI (or deploy on Blaxel)
|
|
59
|
+
|
|
60
|
+
When developing locally, the recommended method is to just log in to your workspace with Blaxel CLI. This allows you to run Blaxel SDK functions that will automatically connect to your workspace without additional setup. When you deploy on Blaxel, this connection persists automatically.
|
|
61
|
+
|
|
62
|
+
When running Blaxel SDK from a remote server that is not Blaxel-hosted, we recommend using environment variables as described in the third option above.
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
## Features
|
|
67
|
+
- Agents & MCP servers
|
|
68
|
+
- [Create MCP servers](https://docs.blaxel.ai/Functions/Create-MCP-server)
|
|
69
|
+
- [Connect to MCP servers and model APIs hosted on Blaxel](https://docs.blaxel.ai/Agents/Develop-an-agent-ts)
|
|
70
|
+
- [Call agents from another agent](https://docs.blaxel.ai/Agents/Develop-an-agent-ts#connect-to-another-agent-multi-agent-chaining)
|
|
71
|
+
- [Deploy on Blaxel](https://docs.blaxel.ai/Agents/Deploy-an-agent)
|
|
72
|
+
- Sandboxes
|
|
73
|
+
- [Create and update sandboxes and sandbox previews](https://docs.blaxel.ai/Sandboxes/Overview)
|
|
74
|
+
- [Run filesystem operations and processes on a sandbox](https://docs.blaxel.ai/Sandboxes/Processes)
|
|
75
|
+
- [Use environment variables or secrets](https://docs.blaxel.ai/Agents/Variables-and-secrets)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Quickstart
|
|
80
|
+
|
|
81
|
+
Blaxel CLI gives you a quick way to create new applications: agents, MCP servers, jobs, etc - and deploy them to Blaxel.
|
|
82
|
+
|
|
83
|
+
**Prerequisites**:
|
|
84
|
+
- **Node.js:** v18 or later.
|
|
85
|
+
- **Blaxel CLI:** Make sure you have Blaxel CLI installed. If not, [install it](https://docs.blaxel.ai/cli-reference/introduction):
|
|
86
|
+
```bash
|
|
87
|
+
curl -fsSL \
|
|
88
|
+
https://raw.githubusercontent.com/blaxel-ai/toolkit/main/install.sh \
|
|
89
|
+
| BINDIR=/usr/local/bin sudo -E sh
|
|
90
|
+
```
|
|
91
|
+
- **Blaxel login:** Login to Blaxel:
|
|
92
|
+
```bash
|
|
93
|
+
bl login YOUR-WORKSPACE
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
bl create-agent-app myfolder
|
|
98
|
+
cd myfolder
|
|
99
|
+
bl deploy
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Also available:
|
|
103
|
+
- `bl create-mcp-server`
|
|
104
|
+
- `bl create-job`
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
## Contributing
|
|
109
|
+
|
|
110
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
@@ -9,6 +9,8 @@ export declare class ClientCredentials extends Credentials {
|
|
|
9
9
|
get workspace(): string;
|
|
10
10
|
needRefresh(): boolean;
|
|
11
11
|
authenticate(): Promise<void>;
|
|
12
|
+
private sleep;
|
|
13
|
+
processWithRetry(retry?: number): Promise<void>;
|
|
12
14
|
process(): Promise<void>;
|
|
13
15
|
get authorization(): string;
|
|
14
16
|
get token(): string;
|
|
@@ -42,9 +42,24 @@ class ClientCredentials extends credentials_js_1.Credentials {
|
|
|
42
42
|
if (!this.needRefresh()) {
|
|
43
43
|
return this.currentPromise || Promise.resolve();
|
|
44
44
|
}
|
|
45
|
-
this.currentPromise = this.
|
|
45
|
+
this.currentPromise = this.processWithRetry();
|
|
46
46
|
return this.currentPromise;
|
|
47
47
|
}
|
|
48
|
+
sleep(ms) {
|
|
49
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
50
|
+
}
|
|
51
|
+
async processWithRetry(retry = 3) {
|
|
52
|
+
try {
|
|
53
|
+
return await this.process();
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
if (retry > 0) {
|
|
57
|
+
await this.sleep(1000);
|
|
58
|
+
return this.processWithRetry(retry - 1);
|
|
59
|
+
}
|
|
60
|
+
throw error;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
48
63
|
async process() {
|
|
49
64
|
const response = await (0, authentication_js_1.oauthToken)({
|
|
50
65
|
headers: {
|
package/dist/jobs/index.d.ts
CHANGED
package/dist/jobs/index.js
CHANGED
|
@@ -15,3 +15,5 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
17
|
__exportStar(require("./jobs.js"), exports);
|
|
18
|
+
__exportStar(require("./start.js"), exports);
|
|
19
|
+
__exportStar(require("./types.js"), exports);
|
package/dist/jobs/jobs.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
declare class BlJob {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
get
|
|
7
|
-
get
|
|
8
|
-
|
|
2
|
+
jobName: string;
|
|
3
|
+
constructor(jobName: string);
|
|
4
|
+
get fallbackUrl(): import("url").URL | null;
|
|
5
|
+
get externalUrl(): import("url").URL;
|
|
6
|
+
get internalUrl(): import("url").URL;
|
|
7
|
+
get forcedUrl(): import("url").URL | null;
|
|
8
|
+
get url(): import("url").URL;
|
|
9
|
+
call(url: URL, tasks: Record<string, unknown>[]): Promise<Response>;
|
|
10
|
+
run(tasks: Record<string, unknown>[]): Promise<string>;
|
|
9
11
|
}
|
|
10
|
-
export declare const blJob: BlJob;
|
|
12
|
+
export declare const blJob: (jobName: string) => BlJob;
|
|
11
13
|
export {};
|
package/dist/jobs/jobs.js
CHANGED
|
@@ -2,54 +2,94 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.blJob = void 0;
|
|
4
4
|
const env_js_1 = require("../common/env.js");
|
|
5
|
+
const internal_js_1 = require("../common/internal.js");
|
|
6
|
+
const logger_js_1 = require("../common/logger.js");
|
|
7
|
+
const settings_js_1 = require("../common/settings.js");
|
|
8
|
+
const telemetry_js_1 = require("../telemetry/telemetry.js");
|
|
5
9
|
class BlJob {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
jobName;
|
|
11
|
+
constructor(jobName) {
|
|
12
|
+
this.jobName = jobName;
|
|
13
|
+
}
|
|
14
|
+
get fallbackUrl() {
|
|
15
|
+
if (this.externalUrl != this.url) {
|
|
16
|
+
return this.externalUrl;
|
|
10
17
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
result[key] = value;
|
|
25
|
-
i++;
|
|
26
|
-
}
|
|
27
|
-
else {
|
|
28
|
-
result[key] = 'true';
|
|
29
|
-
}
|
|
30
|
-
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
get externalUrl() {
|
|
21
|
+
return new URL(`${settings_js_1.settings.runUrl}/${settings_js_1.settings.workspace}/jobs/${this.jobName}`);
|
|
22
|
+
}
|
|
23
|
+
get internalUrl() {
|
|
24
|
+
const hash = (0, internal_js_1.getGlobalUniqueHash)(settings_js_1.settings.workspace, "job", this.jobName);
|
|
25
|
+
return new URL(`${settings_js_1.settings.runInternalProtocol}://bl-${settings_js_1.settings.env}-${hash}.${settings_js_1.settings.runInternalHostname}`);
|
|
26
|
+
}
|
|
27
|
+
get forcedUrl() {
|
|
28
|
+
const envVar = this.jobName.replace(/-/g, "_").toUpperCase();
|
|
29
|
+
if (env_js_1.env[`BL_JOB_${envVar}_URL`]) {
|
|
30
|
+
return new URL(env_js_1.env[`BL_JOB_${envVar}_URL`]);
|
|
31
31
|
}
|
|
32
|
-
return
|
|
32
|
+
return null;
|
|
33
33
|
}
|
|
34
|
-
get
|
|
35
|
-
|
|
34
|
+
get url() {
|
|
35
|
+
if (this.forcedUrl)
|
|
36
|
+
return this.forcedUrl;
|
|
37
|
+
if (settings_js_1.settings.runInternalHostname)
|
|
38
|
+
return this.internalUrl;
|
|
39
|
+
return this.externalUrl;
|
|
36
40
|
}
|
|
37
|
-
|
|
38
|
-
|
|
41
|
+
async call(url, tasks) {
|
|
42
|
+
let body = {
|
|
43
|
+
tasks: tasks
|
|
44
|
+
};
|
|
45
|
+
const response = await fetch(url + "/executions", {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
...settings_js_1.settings.headers,
|
|
49
|
+
"Content-Type": "application/json",
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify(body),
|
|
52
|
+
});
|
|
53
|
+
return response;
|
|
39
54
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
55
|
+
async run(tasks) {
|
|
56
|
+
logger_js_1.logger.debug(`Job Calling: ${this.jobName}`);
|
|
57
|
+
const span = (0, telemetry_js_1.startSpan)(this.jobName, {
|
|
58
|
+
attributes: {
|
|
59
|
+
"job.name": this.jobName,
|
|
60
|
+
"span.type": "job.run",
|
|
61
|
+
},
|
|
62
|
+
isRoot: false,
|
|
63
|
+
});
|
|
44
64
|
try {
|
|
45
|
-
const
|
|
46
|
-
await
|
|
47
|
-
|
|
65
|
+
const response = await this.call(this.url, tasks);
|
|
66
|
+
return await response.text();
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err instanceof Error) {
|
|
70
|
+
if (!this.fallbackUrl) {
|
|
71
|
+
span.setAttribute("job.run.error", err.stack);
|
|
72
|
+
throw err;
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
const response = await this.call(this.fallbackUrl, tasks);
|
|
76
|
+
return await response.text();
|
|
77
|
+
}
|
|
78
|
+
catch (err) {
|
|
79
|
+
if (err instanceof Error) {
|
|
80
|
+
span.setAttribute("job.run.error", err.stack);
|
|
81
|
+
}
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
throw err;
|
|
48
86
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
process.exit(1);
|
|
87
|
+
finally {
|
|
88
|
+
span.end();
|
|
52
89
|
}
|
|
53
90
|
}
|
|
54
91
|
}
|
|
55
|
-
|
|
92
|
+
const blJob = (jobName) => {
|
|
93
|
+
return new BlJob(jobName);
|
|
94
|
+
};
|
|
95
|
+
exports.blJob = blJob;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const blStartJob: (func: (args: any) => Promise<void>) => void;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.blStartJob = void 0;
|
|
4
|
+
const autoload_js_1 = require("../common/autoload.js");
|
|
5
|
+
const env_js_1 = require("../common/env.js");
|
|
6
|
+
const telemetry_js_1 = require("../telemetry/telemetry.js");
|
|
7
|
+
class BlJobWrapper {
|
|
8
|
+
async getArguments() {
|
|
9
|
+
if (!env_js_1.env.BL_EXECUTION_DATA_URL) {
|
|
10
|
+
const args = this.parseCommandLineArgs();
|
|
11
|
+
return args;
|
|
12
|
+
}
|
|
13
|
+
const response = await fetch(env_js_1.env.BL_EXECUTION_DATA_URL);
|
|
14
|
+
const data = await response.json();
|
|
15
|
+
return data.tasks[this.index] ?? {};
|
|
16
|
+
}
|
|
17
|
+
parseCommandLineArgs() {
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const result = {};
|
|
20
|
+
for (let i = 0; i < args.length; i++) {
|
|
21
|
+
const arg = args[i];
|
|
22
|
+
if (arg.startsWith('--')) {
|
|
23
|
+
const key = arg.slice(2);
|
|
24
|
+
const value = args[i + 1];
|
|
25
|
+
if (value && !value.startsWith('--')) {
|
|
26
|
+
result[key] = value;
|
|
27
|
+
i++;
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
result[key] = 'true';
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
get indexKey() {
|
|
37
|
+
return env_js_1.env.BL_TASK_KEY ?? "TASK_INDEX";
|
|
38
|
+
}
|
|
39
|
+
get index() {
|
|
40
|
+
return env_js_1.env[this.indexKey] ? Number(env_js_1.env[this.indexKey]) ?? 0 : 0;
|
|
41
|
+
}
|
|
42
|
+
/*
|
|
43
|
+
Run a job defined in a function, it's run in the current process
|
|
44
|
+
*/
|
|
45
|
+
async start(func) {
|
|
46
|
+
await (0, autoload_js_1.authenticate)();
|
|
47
|
+
let span = (0, telemetry_js_1.startSpan)(`blStartJob-${func.name}`, {
|
|
48
|
+
attributes: {
|
|
49
|
+
'job.name': func.name,
|
|
50
|
+
'job.index': this.index,
|
|
51
|
+
'job.args': JSON.stringify(this.getArguments()),
|
|
52
|
+
},
|
|
53
|
+
isRoot: true,
|
|
54
|
+
});
|
|
55
|
+
try {
|
|
56
|
+
const parsedArgs = await this.getArguments();
|
|
57
|
+
await func(parsedArgs);
|
|
58
|
+
span.setStatus('ok');
|
|
59
|
+
span.end();
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
62
|
+
span.recordException(error);
|
|
63
|
+
span.setStatus('error', 'Job execution failed');
|
|
64
|
+
span.end();
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const blStartJob = (func) => {
|
|
70
|
+
const job = new BlJobWrapper();
|
|
71
|
+
job.start(func).then(async () => {
|
|
72
|
+
try {
|
|
73
|
+
await (0, telemetry_js_1.flush)();
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error('Error flushing telemetry:', error);
|
|
77
|
+
}
|
|
78
|
+
}).catch((error) => {
|
|
79
|
+
console.error('Job execution failed:', error);
|
|
80
|
+
process.exit(1);
|
|
81
|
+
});
|
|
82
|
+
};
|
|
83
|
+
exports.blStartJob = blStartJob;
|
|
@@ -32,6 +32,8 @@ export interface BlaxelSpan {
|
|
|
32
32
|
export interface BlaxelTelemetryProvider {
|
|
33
33
|
/** Create a new span */
|
|
34
34
|
startSpan(name: string, options?: BlaxelSpanOptions): BlaxelSpan;
|
|
35
|
+
/** Flush the telemetry provider */
|
|
36
|
+
flush(): Promise<void>;
|
|
35
37
|
}
|
|
36
38
|
/**
|
|
37
39
|
* Registry for managing the global telemetry provider
|
|
@@ -55,5 +57,6 @@ export declare const telemetryRegistry: TelemetryRegistry;
|
|
|
55
57
|
* Create a span with the registered provider
|
|
56
58
|
*/
|
|
57
59
|
export declare function startSpan(name: string, options?: BlaxelSpanOptions): BlaxelSpan;
|
|
58
|
-
export declare function withSpan<T>(name: string, fn: () => T
|
|
60
|
+
export declare function withSpan<T>(name: string, fn: () => Promise<T>, options?: BlaxelSpanOptions): Promise<T>;
|
|
61
|
+
export declare function flush(): Promise<void>;
|
|
59
62
|
export {};
|
|
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
4
4
|
exports.telemetryRegistry = void 0;
|
|
5
5
|
exports.startSpan = startSpan;
|
|
6
6
|
exports.withSpan = withSpan;
|
|
7
|
+
exports.flush = flush;
|
|
7
8
|
/**
|
|
8
9
|
* No-operation implementation of Span
|
|
9
10
|
*/
|
|
@@ -22,6 +23,9 @@ class NoopTelemetryProvider {
|
|
|
22
23
|
startSpan() {
|
|
23
24
|
return new NoopSpan();
|
|
24
25
|
}
|
|
26
|
+
flush() {
|
|
27
|
+
return Promise.resolve();
|
|
28
|
+
}
|
|
25
29
|
}
|
|
26
30
|
/**
|
|
27
31
|
* Registry for managing the global telemetry provider
|
|
@@ -58,10 +62,10 @@ exports.telemetryRegistry = TelemetryRegistry.getInstance();
|
|
|
58
62
|
function startSpan(name, options) {
|
|
59
63
|
return exports.telemetryRegistry.getProvider().startSpan(name, options);
|
|
60
64
|
}
|
|
61
|
-
function withSpan(name, fn, options) {
|
|
65
|
+
async function withSpan(name, fn, options) {
|
|
62
66
|
const span = startSpan(name, options);
|
|
63
67
|
try {
|
|
64
|
-
const result = fn();
|
|
68
|
+
const result = await fn();
|
|
65
69
|
span.end();
|
|
66
70
|
return result;
|
|
67
71
|
}
|
|
@@ -71,3 +75,6 @@ function withSpan(name, fn, options) {
|
|
|
71
75
|
throw error;
|
|
72
76
|
}
|
|
73
77
|
}
|
|
78
|
+
async function flush() {
|
|
79
|
+
await exports.telemetryRegistry.getProvider().flush();
|
|
80
|
+
}
|