boids-sdk 0.1.1 → 0.1.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 CHANGED
@@ -5,18 +5,21 @@ JavaScript SDK and CLI for the Boids API.
5
5
  ## Install
6
6
 
7
7
  ```bash
8
- npm install boids-sdk
8
+ curl -fsSL https://raw.githubusercontent.com/NevaMind-AI/boids-sdk/main/install.sh | bash
9
9
  export BOIDS_API_KEY="..."
10
10
  ```
11
11
 
12
+ The installer tries `npm install -g boids-sdk` first, then falls back to pipx or
13
+ pip. Use `npm install boids-sdk` for a project-local SDK dependency.
14
+
12
15
  ## CLI
13
16
 
14
17
  ```bash
15
- boids agent:@iris-wei-org/my-doppelganger "Introduce yourself in one sentence."
18
+ boids agent:@boids-team/jarvis "Introduce yourself in one sentence."
16
19
  boids search "global launch growth agent" --limit 5
17
20
  boids run "Create a launch plan for a developer tool."
18
- boids agent:@iris-wei-org/my-doppelganger "Remember my name is Ada." --show-response-id
19
- boids agent:@iris-wei-org/my-doppelganger "What is my name?" --prev resp_...
21
+ boids agent:@boids-team/jarvis "Remember my name is Ada." --show-response-id
22
+ boids agent:@boids-team/jarvis "What is my name?" --prev resp_...
20
23
  ```
21
24
 
22
25
  `boids run` searches `/v1/market/search`, selects the first returned agent, and
@@ -30,17 +33,27 @@ import { Boids } from "boids-sdk";
30
33
  const client = new Boids();
31
34
 
32
35
  const response = await client.responses.create({
33
- model: "agent:@iris-wei-org/my-doppelganger",
36
+ model: "agent:@boids-team/jarvis",
34
37
  input: "Introduce yourself in one sentence.",
35
38
  });
36
39
  console.log(response);
37
40
  ```
38
41
 
42
+ Chat complete:
43
+
44
+ ```js
45
+ const response = await client.chat.complete({
46
+ model: "agent:@boids-team/jarvis",
47
+ messages: [{ role: "user", content: "Introduce yourself in one sentence." }],
48
+ });
49
+ console.log(response);
50
+ ```
51
+
39
52
  Streaming:
40
53
 
41
54
  ```js
42
55
  for await (const event of client.responses.create({
43
- model: "agent:@iris-wei-org/my-doppelganger",
56
+ model: "agent:@boids-team/jarvis",
44
57
  input: "Introduce yourself in one sentence.",
45
58
  stream: true,
46
59
  })) {
@@ -62,12 +75,12 @@ Conversation context:
62
75
 
63
76
  ```js
64
77
  const first = await client.responses.create({
65
- model: "agent:@iris-wei-org/my-doppelganger",
78
+ model: "agent:@boids-team/jarvis",
66
79
  input: "Remember my name is Ada.",
67
80
  });
68
81
 
69
82
  const second = await client.responses.create({
70
- model: "agent:@iris-wei-org/my-doppelganger",
83
+ model: "agent:@boids-team/jarvis",
71
84
  input: "What is my name?",
72
85
  previous_response_id: first.id,
73
86
  });
package/bin/boids.js CHANGED
@@ -96,6 +96,23 @@ async function main(argv) {
96
96
  return 0;
97
97
  }
98
98
 
99
+ if (command === "chat") {
100
+ const options = parseOptions(argv);
101
+ const model = requireModel(options.model);
102
+ const input = options.input ?? options._.join(" ");
103
+
104
+ const client = makeClient(options);
105
+ const result = client.chat.complete({
106
+ model,
107
+ messages: chatMessages(input, options.messages),
108
+ stream: Boolean(options.stream),
109
+ });
110
+ await printResult(result, Boolean(options.json), {
111
+ showResponseId: Boolean(options.showResponseId),
112
+ });
113
+ return 0;
114
+ }
115
+
99
116
  throw new Error(`Unknown command: ${command}`);
100
117
  }
101
118
 
@@ -285,6 +302,9 @@ function parseOptions(args, { envModel = true } = {}) {
285
302
  options.searchQuery = args[++index];
286
303
  } else if (arg === "--limit") {
287
304
  options.limit = args[++index];
305
+ } else if (arg === "--message") {
306
+ options.messages ??= [];
307
+ options.messages.push(args[++index]);
288
308
  } else if (arg === "--previous-response-id" || arg === "--prev") {
289
309
  options.previousResponseId = args[++index];
290
310
  } else if (arg === "--api-key") {
@@ -301,6 +321,9 @@ function parseOptions(args, { envModel = true } = {}) {
301
321
  options.searchQuery = arg.slice("--search-query=".length);
302
322
  } else if (arg.startsWith("--limit=")) {
303
323
  options.limit = arg.slice("--limit=".length);
324
+ } else if (arg.startsWith("--message=")) {
325
+ options.messages ??= [];
326
+ options.messages.push(arg.slice("--message=".length));
304
327
  } else if (arg.startsWith("--previous-response-id=")) {
305
328
  options.previousResponseId = arg.slice("--previous-response-id=".length);
306
329
  } else if (arg.startsWith("--prev=")) {
@@ -327,6 +350,27 @@ function requireModel(model) {
327
350
  throw new Error("Missing --model or BOIDS_MODEL.");
328
351
  }
329
352
 
353
+ function chatMessages(input, rawMessages = []) {
354
+ const messages = [];
355
+ for (const rawMessage of rawMessages) {
356
+ const separator = rawMessage.indexOf(":");
357
+ const role = separator === -1 ? "" : rawMessage.slice(0, separator);
358
+ const content = separator === -1 ? "" : rawMessage.slice(separator + 1);
359
+ if (!role || !content) {
360
+ throw new Error("--message must be formatted as role:content.");
361
+ }
362
+ messages.push({ role, content });
363
+ }
364
+
365
+ if (input) {
366
+ messages.push({ role: "user", content: input });
367
+ }
368
+ if (messages.length === 0) {
369
+ throw new Error("Missing --input, --message, or input text.");
370
+ }
371
+ return messages;
372
+ }
373
+
330
374
  function isAsyncIterable(value) {
331
375
  return value && typeof value[Symbol.asyncIterator] === "function";
332
376
  }
@@ -354,7 +398,7 @@ function printResponseId(value) {
354
398
 
355
399
  function looksLikeShortcut(args) {
356
400
  const first = firstPositional(args);
357
- return first !== undefined && !["ask", "responses", "search", "run", "auto"].includes(first);
401
+ return first !== undefined && !["ask", "responses", "chat", "search", "run", "auto"].includes(first);
358
402
  }
359
403
 
360
404
  function firstPositional(args) {
@@ -370,6 +414,7 @@ function firstPositional(args) {
370
414
  "-q",
371
415
  "--search-query",
372
416
  "--limit",
417
+ "--message",
373
418
  "--previous-response-id",
374
419
  "--prev",
375
420
  ]);
@@ -393,6 +438,7 @@ function firstPositional(args) {
393
438
  arg.startsWith("--query=") ||
394
439
  arg.startsWith("--search-query=") ||
395
440
  arg.startsWith("--limit=") ||
441
+ arg.startsWith("--message=") ||
396
442
  arg.startsWith("--previous-response-id=") ||
397
443
  arg.startsWith("--prev=")
398
444
  ) {
@@ -416,6 +462,7 @@ function usage() {
416
462
  boids run <input> [--search-query <query>] [--prev <response-id>]
417
463
  boids ask --model <model> [--no-stream] <input>
418
464
  boids responses create --model <model> --input <input> [--stream] [--prev <response-id>]
465
+ boids chat --model <model> --input <input> [--stream]
419
466
 
420
467
  Environment:
421
468
  BOIDS_API_KEY Required API key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "boids-sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "JavaScript SDK and CLI for the Boids Responses API",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.d.ts CHANGED
@@ -19,6 +19,19 @@ export interface ResponseEvent {
19
19
  raw: string;
20
20
  }
21
21
 
22
+ export interface ChatMessage {
23
+ role: string;
24
+ content: unknown;
25
+ [key: string]: unknown;
26
+ }
27
+
28
+ export interface ChatCompleteParams {
29
+ model: string;
30
+ messages: ChatMessage[];
31
+ stream?: boolean;
32
+ [key: string]: unknown;
33
+ }
34
+
22
35
  export interface MarketSearchParams {
23
36
  query: string;
24
37
  limit?: number;
@@ -37,10 +50,14 @@ export class Boids {
37
50
  responses: {
38
51
  create(params: ResponseCreateParams): Promise<unknown> | AsyncIterable<ResponseEvent>;
39
52
  };
53
+ chat: {
54
+ complete(params: ChatCompleteParams): Promise<unknown> | AsyncIterable<ResponseEvent>;
55
+ };
40
56
  market: {
41
57
  search(params: MarketSearchParams | string): Promise<unknown>;
42
58
  };
43
59
  createResponse(params: ResponseCreateParams): Promise<unknown> | AsyncIterable<ResponseEvent>;
60
+ completeChat(params: ChatCompleteParams): Promise<unknown> | AsyncIterable<ResponseEvent>;
44
61
  searchMarket(params: MarketSearchParams | string): Promise<unknown>;
45
62
  }
46
63
 
package/src/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const DEFAULT_BASE_URL = "https://api.boids.so/v1";
2
- const USER_AGENT = "boids-sdk-js/0.1.1";
2
+ const USER_AGENT = "boids-sdk-js/0.1.2";
3
3
 
4
4
  export class BoidsError extends Error {
5
5
  constructor(message) {
@@ -29,6 +29,9 @@ export class Boids {
29
29
  this.responses = {
30
30
  create: (params) => this.createResponse(params),
31
31
  };
32
+ this.chat = {
33
+ complete: (params) => this.completeChat(params),
34
+ };
32
35
  this.market = {
33
36
  search: (params) => this.searchMarket(params),
34
37
  };
@@ -42,6 +45,14 @@ export class Boids {
42
45
  return this.requestJSON("/responses", body);
43
46
  }
44
47
 
48
+ completeChat(params = {}) {
49
+ const body = withoutUndefined({ ...params });
50
+ if (body.stream) {
51
+ return this.streamChatCompletion(body);
52
+ }
53
+ return this.requestJSON("/chat/complete", body);
54
+ }
55
+
45
56
  async requestJSON(path, body) {
46
57
  const response = await this.request(path, body);
47
58
  const text = await response.text();
@@ -67,6 +78,11 @@ export class Boids {
67
78
  yield* parseSSE(response);
68
79
  }
69
80
 
81
+ async *streamChatCompletion(body) {
82
+ const response = await this.request("/chat/complete", { ...body, stream: true });
83
+ yield* parseSSE(response);
84
+ }
85
+
70
86
  async request(path, body) {
71
87
  if (!this.apiKey) {
72
88
  throw new BoidsError("Missing BOIDS_API_KEY or apiKey.");