@asterai/cli 0.3.2 → 0.5.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.
@@ -0,0 +1,93 @@
1
+ import { Flags, Command } from "@oclif/core";
2
+ import readline from "node:readline";
3
+ import { AsteraiClient } from "@asterai/client";
4
+ import { v4 as uuidv4 } from "uuid";
5
+ const ANSI_COLORS = {
6
+ reset: "\x1b[0m",
7
+ bold: "\u001b[1m",
8
+ };
9
+ const USER_PREFIX = `${ANSI_COLORS.bold}user: ${ANSI_COLORS.reset}`;
10
+ const ASSISTANT_PREFIX = `${ANSI_COLORS.bold}assistant: ${ANSI_COLORS.reset}`;
11
+ const PRODUCTION_BASE_URL = "https://api.asterai.io";
12
+ const STAGING_BASE_URL = "https://staging.api.asterai.io";
13
+ export default class Query extends Command {
14
+ static args = {};
15
+ static description = "query an asterai app interactively";
16
+ static examples = [`<%= config.bin %> <%= command.id %>`];
17
+ static flags = {
18
+ app: Flags.string({
19
+ char: "a",
20
+ required: true,
21
+ }),
22
+ key: Flags.string({
23
+ char: "k",
24
+ required: true,
25
+ description: "app query key",
26
+ }),
27
+ staging: Flags.boolean({
28
+ char: "s",
29
+ }),
30
+ endpoint: Flags.string({
31
+ char: "e",
32
+ default: PRODUCTION_BASE_URL,
33
+ }),
34
+ };
35
+ async run() {
36
+ console.clear();
37
+ const { flags } = await this.parse(Query);
38
+ let output = "";
39
+ const addToOutput = (v) => {
40
+ output += v;
41
+ };
42
+ const apiBaseUrl = flags.staging ? STAGING_BASE_URL : flags.endpoint;
43
+ const client = new AsteraiClient({
44
+ appId: flags.app,
45
+ queryKey: flags.key,
46
+ apiBaseUrl,
47
+ });
48
+ const conversationId = uuidv4();
49
+ // Configure STDIN for when raw mode is enabled.
50
+ process.stdin.setEncoding("utf8");
51
+ process.stdin.on("data", key => {
52
+ if (key.toString() === "\u0003") {
53
+ process.stdout.write("\n");
54
+ process.exit();
55
+ }
56
+ });
57
+ const getUserInput = async () => {
58
+ addToOutput(USER_PREFIX);
59
+ const rl = readline.createInterface({
60
+ input: process.stdin,
61
+ output: process.stdout,
62
+ });
63
+ const input = await new Promise(resolve => rl.question(USER_PREFIX, i => resolve(i)));
64
+ rl.close();
65
+ // Enable raw mode to prevent STDIN from echoing in STDOUT.
66
+ process.stdin.setRawMode(true);
67
+ addToOutput(`${input}\r\n${ASSISTANT_PREFIX}`);
68
+ console.clear();
69
+ process.stdout.write(output);
70
+ const query = {
71
+ query: input,
72
+ conversationId,
73
+ };
74
+ const response = await client.query(query);
75
+ response.onToken(token => {
76
+ addToOutput(token);
77
+ process.stdout.write(token);
78
+ });
79
+ return new Promise(resolve => {
80
+ response.onEnd(() => {
81
+ addToOutput("\n");
82
+ process.stdout.write("\n");
83
+ // Disable raw mode to prepare for next user input.
84
+ process.stdin.setRawMode(false);
85
+ resolve(undefined);
86
+ });
87
+ });
88
+ };
89
+ while (true) {
90
+ await getUserInput();
91
+ }
92
+ }
93
+ }
@@ -0,0 +1,2 @@
1
+ export declare const BASE_API_URL = "https://api.asterai.io";
2
+ export declare const BASE_API_URL_STAGING = "https://staging.api.asterai.io";
package/dist/const.js ADDED
@@ -0,0 +1,2 @@
1
+ export const BASE_API_URL = "https://api.asterai.io";
2
+ export const BASE_API_URL_STAGING = "https://staging.api.asterai.io";
@@ -28,24 +28,49 @@
28
28
  "auth.js"
29
29
  ]
30
30
  },
31
- "build": {
31
+ "deploy": {
32
32
  "aliases": [],
33
- "args": {
34
- "input": {
35
- "default": "plugin.ts",
36
- "name": "input"
37
- }
38
- },
39
- "description": "compiles the plugin",
33
+ "args": {},
34
+ "description": "uploads a plugin to asterai",
40
35
  "examples": [
41
- "<%= config.bin %> <%= command.id %>"
36
+ "<%= config.bin %> <%= command.id %> --app 66a46b12-b1a7-4b72-a64a-0e4fe21902b6"
42
37
  ],
43
38
  "flags": {
44
- "manifest": {
45
- "char": "m",
46
- "description": "manifest path",
47
- "name": "manifest",
48
- "default": "plugin.asterai.proto",
39
+ "agent": {
40
+ "char": "a",
41
+ "description": "agent ID to immediately activate this plugin for",
42
+ "name": "agent",
43
+ "required": false,
44
+ "hasDynamicHelp": false,
45
+ "multiple": false,
46
+ "type": "option"
47
+ },
48
+ "endpoint": {
49
+ "char": "e",
50
+ "name": "endpoint",
51
+ "default": "https://api.asterai.io",
52
+ "hasDynamicHelp": false,
53
+ "multiple": false,
54
+ "type": "option"
55
+ },
56
+ "staging": {
57
+ "char": "s",
58
+ "name": "staging",
59
+ "allowNo": false,
60
+ "type": "boolean"
61
+ },
62
+ "plugin": {
63
+ "description": "plugin WASM path",
64
+ "name": "plugin",
65
+ "default": "plugin.wasm",
66
+ "hasDynamicHelp": false,
67
+ "multiple": false,
68
+ "type": "option"
69
+ },
70
+ "pkg": {
71
+ "description": "package WASM path",
72
+ "name": "pkg",
73
+ "default": "package.wasm",
49
74
  "hasDynamicHelp": false,
50
75
  "multiple": false,
51
76
  "type": "option"
@@ -53,7 +78,7 @@
53
78
  },
54
79
  "hasDynamicHelp": false,
55
80
  "hiddenAliases": [],
56
- "id": "build",
81
+ "id": "deploy",
57
82
  "pluginAlias": "@asterai/cli",
58
83
  "pluginName": "@asterai/cli",
59
84
  "pluginType": "core",
@@ -63,66 +88,25 @@
63
88
  "relativePath": [
64
89
  "dist",
65
90
  "commands",
66
- "build.js"
91
+ "deploy.js"
67
92
  ]
68
93
  },
69
- "codegen": {
94
+ "init": {
70
95
  "aliases": [],
71
- "args": {},
72
- "description": "Generate code from the plugin manifest",
73
- "examples": [
74
- "<%= config.bin %> <%= command.id %>"
75
- ],
76
- "flags": {
77
- "manifest": {
78
- "char": "m",
79
- "description": "manifest path",
80
- "name": "manifest",
81
- "default": "plugin.asterai.proto",
82
- "hasDynamicHelp": false,
83
- "multiple": false,
84
- "type": "option"
85
- },
86
- "outputDir": {
87
- "char": "o",
88
- "description": "output directory",
89
- "name": "outputDir",
90
- "default": "generated",
91
- "hasDynamicHelp": false,
92
- "multiple": false,
93
- "type": "option"
94
- },
95
- "appId": {
96
- "char": "a",
97
- "description": "app id",
98
- "name": "appId",
99
- "required": false,
100
- "hasDynamicHelp": false,
101
- "multiple": false,
102
- "type": "option"
103
- },
104
- "language": {
105
- "char": "l",
106
- "description": "language of generated typings",
107
- "name": "language",
108
- "required": false,
109
- "default": "js",
110
- "hasDynamicHelp": false,
111
- "multiple": false,
112
- "type": "option"
113
- },
114
- "staging": {
115
- "char": "s",
116
- "description": "use staging endpoint",
117
- "name": "staging",
118
- "required": false,
119
- "allowNo": false,
120
- "type": "boolean"
96
+ "args": {
97
+ "outDir": {
98
+ "default": "plugin",
99
+ "name": "outDir"
121
100
  }
122
101
  },
102
+ "description": "Initialise a new plugin project",
103
+ "examples": [
104
+ "<%= config.bin %> <%= command.id %> project-name"
105
+ ],
106
+ "flags": {},
123
107
  "hasDynamicHelp": false,
124
108
  "hiddenAliases": [],
125
- "id": "codegen",
109
+ "id": "init",
126
110
  "pluginAlias": "@asterai/cli",
127
111
  "pluginName": "@asterai/cli",
128
112
  "pluginType": "core",
@@ -132,36 +116,37 @@
132
116
  "relativePath": [
133
117
  "dist",
134
118
  "commands",
135
- "codegen.js"
119
+ "init.js"
136
120
  ]
137
121
  },
138
- "deploy": {
122
+ "pkg": {
139
123
  "aliases": [],
140
124
  "args": {
141
125
  "input": {
142
- "default": "plugin.ts",
126
+ "default": "plugin.wit",
127
+ "description": "path to the plugin's WIT file",
143
128
  "name": "input"
144
129
  }
145
130
  },
146
- "description": "compiles and uploads the plugin to asterai",
131
+ "description": "bundles the WIT into a binary WASM package",
147
132
  "examples": [
148
- "<%= config.bin %> <%= command.id %> --app 66a46b12-b1a7-4b72-a64a-0e4fe21902b6"
133
+ "<%= config.bin %> <%= command.id %>"
149
134
  ],
150
135
  "flags": {
151
- "app": {
152
- "char": "a",
153
- "description": "app ID to immediately configure this plugin with",
154
- "name": "app",
155
- "required": true,
136
+ "output": {
137
+ "char": "o",
138
+ "description": "output file name for the binary WASM package",
139
+ "name": "output",
140
+ "default": "package.wasm",
156
141
  "hasDynamicHelp": false,
157
142
  "multiple": false,
158
143
  "type": "option"
159
144
  },
160
- "manifest": {
161
- "char": "m",
162
- "description": "manifest path",
163
- "name": "manifest",
164
- "default": "plugin.asterai.proto",
145
+ "wit": {
146
+ "char": "w",
147
+ "description": "output package converted to the WIT format",
148
+ "name": "wit",
149
+ "default": "package.wit",
165
150
  "hasDynamicHelp": false,
166
151
  "multiple": false,
167
152
  "type": "option"
@@ -169,21 +154,15 @@
169
154
  "endpoint": {
170
155
  "char": "e",
171
156
  "name": "endpoint",
172
- "default": "https://api.asterai.io/app/plugin",
157
+ "default": "https://api.asterai.io",
173
158
  "hasDynamicHelp": false,
174
159
  "multiple": false,
175
160
  "type": "option"
176
- },
177
- "staging": {
178
- "char": "s",
179
- "name": "staging",
180
- "allowNo": false,
181
- "type": "boolean"
182
161
  }
183
162
  },
184
163
  "hasDynamicHelp": false,
185
164
  "hiddenAliases": [],
186
- "id": "deploy",
165
+ "id": "pkg",
187
166
  "pluginAlias": "@asterai/cli",
188
167
  "pluginName": "@asterai/cli",
189
168
  "pluginType": "core",
@@ -193,25 +172,52 @@
193
172
  "relativePath": [
194
173
  "dist",
195
174
  "commands",
196
- "deploy.js"
175
+ "pkg.js"
197
176
  ]
198
177
  },
199
- "init": {
178
+ "query": {
200
179
  "aliases": [],
201
- "args": {
202
- "outDir": {
203
- "default": "plugin",
204
- "name": "outDir"
205
- }
206
- },
207
- "description": "Initialise a new plugin project",
180
+ "args": {},
181
+ "description": "query an asterai app interactively",
208
182
  "examples": [
209
- "<%= config.bin %> <%= command.id %> project-name"
183
+ "<%= config.bin %> <%= command.id %>"
210
184
  ],
211
- "flags": {},
185
+ "flags": {
186
+ "app": {
187
+ "char": "a",
188
+ "name": "app",
189
+ "required": true,
190
+ "hasDynamicHelp": false,
191
+ "multiple": false,
192
+ "type": "option"
193
+ },
194
+ "key": {
195
+ "char": "k",
196
+ "description": "app query key",
197
+ "name": "key",
198
+ "required": true,
199
+ "hasDynamicHelp": false,
200
+ "multiple": false,
201
+ "type": "option"
202
+ },
203
+ "staging": {
204
+ "char": "s",
205
+ "name": "staging",
206
+ "allowNo": false,
207
+ "type": "boolean"
208
+ },
209
+ "endpoint": {
210
+ "char": "e",
211
+ "name": "endpoint",
212
+ "default": "https://api.asterai.io",
213
+ "hasDynamicHelp": false,
214
+ "multiple": false,
215
+ "type": "option"
216
+ }
217
+ },
212
218
  "hasDynamicHelp": false,
213
219
  "hiddenAliases": [],
214
- "id": "init",
220
+ "id": "query",
215
221
  "pluginAlias": "@asterai/cli",
216
222
  "pluginName": "@asterai/cli",
217
223
  "pluginType": "core",
@@ -221,9 +227,9 @@
221
227
  "relativePath": [
222
228
  "dist",
223
229
  "commands",
224
- "init.js"
230
+ "query.js"
225
231
  ]
226
232
  }
227
233
  },
228
- "version": "0.3.2"
234
+ "version": "0.5.0"
229
235
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@asterai/cli",
3
3
  "description": "CLI for building and deploying asterai plugins",
4
- "version": "0.3.2",
4
+ "version": "0.5.0",
5
5
  "author": "asterai <support@asterai.io>",
6
6
  "repository": "asterai-io/asterai-sdk",
7
7
  "homepage": "https://github.com/asterai-io/asterai-sdk",
@@ -51,6 +51,7 @@
51
51
  "types": "dist/index.d.ts",
52
52
  "dependencies": {
53
53
  "@asterai/as-proto-gen": "^1.4.1",
54
+ "@asterai/client": "^0.1.1",
54
55
  "@oclif/core": "^3",
55
56
  "@oclif/plugin-help": "^6",
56
57
  "@oclif/plugin-plugins": "^5",
@@ -59,7 +60,8 @@
59
60
  "form-data": "^4.0.0",
60
61
  "mustache": "^4.2.0",
61
62
  "protobufjs": "^7.4.0",
62
- "protobufjs-cli": "^1.1.3"
63
+ "protobufjs-cli": "^1.1.3",
64
+ "uuid": "^11.0.2"
63
65
  },
64
66
  "devDependencies": {
65
67
  "@oclif/prettier-config": "^0.2.1",
@@ -1,22 +0,0 @@
1
- syntax = "proto3";
2
- import "node_modules/@asterai/sdk/protobuf/asterai.proto";
3
-
4
- service Math {
5
- rpc processQuery(PluginContext) returns (ProcessQueryOutput);
6
- rpc add(BinaryOperationInput) returns (CalculationOutput);
7
- rpc mul(BinaryOperationInput) returns (CalculationOutput);
8
- rpc div(BinaryOperationInput) returns (CalculationOutput);
9
- rpc pow(BinaryOperationInput) returns (CalculationOutput);
10
- }
11
-
12
- message ProcessQueryOutput {}
13
-
14
- message BinaryOperationInput {
15
- PluginContext context = 1;
16
- double a = 2;
17
- double b = 3;
18
- }
19
-
20
- message CalculationOutput {
21
- string system_message = 1;
22
- }
@@ -1,23 +0,0 @@
1
- import { Command } from "@oclif/core";
2
- export type BuildArgs = {
3
- input: string;
4
- };
5
- export type BuildFlags = {
6
- manifest: string;
7
- };
8
- export type BuildOutput = {
9
- outputFile: string;
10
- manifestPath: string;
11
- };
12
- export default class Build extends Command {
13
- static args: {
14
- input: import("@oclif/core/lib/interfaces/parser.js").Arg<string, Record<string, unknown>>;
15
- };
16
- static description: string;
17
- static examples: string[];
18
- static flags: {
19
- manifest: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
20
- };
21
- run(): Promise<void>;
22
- }
23
- export declare const build: (args: BuildArgs, flags: BuildFlags) => Promise<BuildOutput>;
@@ -1,139 +0,0 @@
1
- import { Args, Command, Flags } from "@oclif/core";
2
- import path from "path";
3
- import fs from "fs";
4
- import { compile } from "../compile.js";
5
- import Mustache from "mustache";
6
- import protobuf from "protobufjs";
7
- import { mergeProtoImports } from "./deploy.js";
8
- export default class Build extends Command {
9
- static args = {
10
- input: Args.string({
11
- default: "plugin.ts",
12
- }),
13
- };
14
- static description = "compiles the plugin";
15
- static examples = [`<%= config.bin %> <%= command.id %>`];
16
- static flags = {
17
- manifest: Flags.string({
18
- char: "m",
19
- description: "manifest path",
20
- default: "plugin.asterai.proto",
21
- }),
22
- };
23
- async run() {
24
- const { args, flags } = await this.parse(Build);
25
- await build(args, flags);
26
- }
27
- }
28
- export const build = async (args, flags) => {
29
- const manifestPath = path.resolve(flags.manifest);
30
- const inputFile = path.resolve(args.input);
31
- if (!fs.existsSync(inputFile)) {
32
- throw new Error(`input file not found (${args.input})`);
33
- }
34
- const inputFileName = path.parse(inputFile).name;
35
- const baseDir = path.dirname(manifestPath);
36
- const outDir = path.join(baseDir, "build");
37
- const outputFile = path.join(outDir, `${inputFileName}.wasm`);
38
- const libsDir = path.join(baseDir, "node_modules");
39
- if (!fs.existsSync(libsDir)) {
40
- throw new Error("no node_modules found in the plugin directory");
41
- }
42
- const proto = fs.readFileSync(manifestPath, { encoding: "utf8" });
43
- const functionDescriptors = getPluginFunctionDescriptors(proto, manifestPath);
44
- const inputFileContent = fs.readFileSync(inputFile, { encoding: "utf8" });
45
- assertPluginCodeHasAllFunctionsFromManifest(inputFileContent, functionDescriptors);
46
- const entryPointCode = generateEntryPointCode(functionDescriptors);
47
- const mergedPluginCode = mergeInputPluginCodeWithEntrypoint(inputFileContent, entryPointCode);
48
- const mergedTempFilePath = writeMergedPluginCodeTempFile(mergedPluginCode, path.parse(inputFile).dir, inputFileName);
49
- const globalFile = path.join(libsDir, "@asterai/sdk/global.ts");
50
- const options = {
51
- inputFiles: [mergedTempFilePath, globalFile],
52
- baseDir,
53
- outputFile,
54
- libs: libsDir,
55
- };
56
- try {
57
- await compile(options);
58
- }
59
- finally {
60
- fs.unlinkSync(mergedTempFilePath);
61
- }
62
- return {
63
- manifestPath,
64
- outputFile,
65
- };
66
- };
67
- const getPluginFunctionDescriptors = (proto, protoPath) => {
68
- const protoMerged = mergeProtoImports(proto, protoPath, false, false);
69
- const result = protobuf.parse(protoMerged);
70
- const namespace = result.root.resolveAll();
71
- const objects = namespace.nestedArray;
72
- const serviceObject = objects.find(o => o.methods !== undefined);
73
- if (!serviceObject) {
74
- throw new Error("no service found in plugin manifest");
75
- }
76
- const service = serviceObject;
77
- return service.methodsArray.map(m => ({
78
- functionName: m.name,
79
- inputType: m.requestType,
80
- outputType: m.responseType,
81
- }));
82
- };
83
- const generateEntryPointCode = (functionDescriptors) => {
84
- const importsCode = `
85
- import { Protobuf } from "@asterai/as-proto/assembly";
86
- import { readBufferFromPtr, writeBufferToPr } from "@asterai/sdk/buffer";
87
- `;
88
- let code = "\n// generated plugin entry points\n\n";
89
- for (const functionDescriptor of functionDescriptors) {
90
- const template = `
91
- export function {{func}}_entry_point(ptr: u32): u32 {
92
- const inputBuffer = readBufferFromPtr(ptr);
93
- const input = Protobuf.decode<{{inpt}}>(
94
- inputBuffer,
95
- {{inpt}}.decode,
96
- );
97
- const output = {{func}}(input);
98
- const outputBuffer = Protobuf.encode<{{outp}}>(
99
- output,
100
- {{outp}}.encode,
101
- );
102
- return writeBufferToPr(outputBuffer);
103
- }
104
- `;
105
- const view = {
106
- func: functionDescriptor.functionName,
107
- inpt: functionDescriptor.inputType,
108
- outp: functionDescriptor.outputType,
109
- };
110
- const functionEntryPoint = Mustache.render(template, view);
111
- code = `${code}\n${functionEntryPoint}`;
112
- }
113
- return {
114
- importsCode,
115
- entryPointsCode: code,
116
- };
117
- };
118
- const mergeInputPluginCodeWithEntrypoint = (pluginCode, entryPoint) => `${entryPoint.importsCode}\n${pluginCode}\n${entryPoint.entryPointsCode}`;
119
- const writeMergedPluginCodeTempFile = (source, inputFileDir, inputFileName) => {
120
- const tempFileName = `.entrypoint.${inputFileName}.ts`;
121
- const tempFilePath = path.join(inputFileDir, tempFileName);
122
- fs.writeFileSync(tempFilePath, source, { encoding: "utf8" });
123
- return tempFilePath;
124
- };
125
- /**
126
- * Throw an error if the plugin WASM source is missing a function from
127
- * the manifest.
128
- * The only purpose of this function is to let the user know about
129
- * the issue in a direct way.
130
- */
131
- const assertPluginCodeHasAllFunctionsFromManifest = (source, functionDescriptors) => {
132
- for (const functionDescriptor of functionDescriptors) {
133
- const includesFunction = source.includes(`function ${functionDescriptor.functionName}`);
134
- if (!includesFunction) {
135
- throw new Error(`function "${functionDescriptor.functionName}" was defined in plugin ` +
136
- "manifest (.proto file) but is missing from plugin code");
137
- }
138
- }
139
- };
@@ -1,22 +0,0 @@
1
- import { Command } from "@oclif/core";
2
- export type CodegenFlags = {
3
- manifest: string;
4
- outputDir: string;
5
- appId?: string;
6
- language?: string;
7
- staging?: boolean;
8
- };
9
- export default class Codegen extends Command {
10
- static args: {};
11
- static description: string;
12
- static examples: string[];
13
- static flags: {
14
- manifest: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
15
- outputDir: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
16
- appId: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
17
- language: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
18
- staging: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<boolean>;
19
- };
20
- run(): Promise<void>;
21
- }
22
- export declare const codegen: (flags: CodegenFlags) => Promise<void>;