@aisa-one/cli 0.6.2 → 0.6.4

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 CHANGED
@@ -7,6 +7,30 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.6.4] — 2026-09-30
11
+
12
+ ### Fixed
13
+
14
+ - Increase the default HTTP timeout from 30 to 600 seconds per attempt to match
15
+ the Router downstream default, allowing long-running tool calls to finish.
16
+ Preserve explicit timeout overrides and existing retry policies.
17
+
18
+ ## [0.6.3] — 2026-09-30
19
+
20
+ ### Changed
21
+
22
+ - Default `aisa chat` to `deepseek-v4.1-flash` for new configurations and
23
+ when no model is configured. Preserve saved `defaultModel` and `--model` overrides.
24
+
25
+ ### Fixed
26
+
27
+ - Display metered provider and endpoint catalog pricing as `usage-based` in
28
+ `api list` and `api show`, rather than treating `normal: 0` as free.
29
+ - Label the catalog price column `PRICING` and show usage-based details as
30
+ `Pricing: usage-based (cost varies)`, with guidance to request a quote.
31
+ - Include `pricing_note` with quote guidance on metered providers and endpoints
32
+ in catalog JSON, preserving the original pricing metadata and list structure.
33
+
10
34
  ## [0.6.2] — 2026-09-23
11
35
 
12
36
  ### Added
@@ -461,7 +485,9 @@ supports today; nothing here depends on a backend change.
461
485
  - Config commands (`aisa config get|set|list|reset`) and auth
462
486
  (`aisa login|logout|whoami`).
463
487
 
464
- [Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.2...HEAD
488
+ [Unreleased]: https://github.com/AIsa-team/cli/compare/v0.6.4...HEAD
489
+ [0.6.4]: https://github.com/AIsa-team/cli/compare/v0.6.3...v0.6.4
490
+ [0.6.3]: https://github.com/AIsa-team/cli/compare/v0.6.2...v0.6.3
465
491
  [0.6.2]: https://github.com/AIsa-team/cli/compare/v0.6.1...v0.6.2
466
492
  [0.6.1]: https://github.com/AIsa-team/cli/compare/v0.6.0...v0.6.1
467
493
  [0.6.0]: https://github.com/AIsa-team/cli/compare/v0.5.2...v0.6.0
package/README.md CHANGED
@@ -31,7 +31,7 @@ aisa quote --input '{"calls":[{"call_id":"c1","tool":"get_financial_company_fact
31
31
 
32
32
  `aisa login` opens a browser, signs you in, and stores OAuth tokens. You do not
33
33
  need to create or paste a key from the console. For CI or scripts, set
34
- `AISA_API_KEY` or run `aisa login --key <key>`. New accounts receive $5 in
34
+ `AISA_API_KEY` or run `aisa login --key <key>`. New accounts receive $1 in
35
35
  free credits.
36
36
 
37
37
  This first block does not run `aisa chat` or `aisa call`. Quote is a price
@@ -141,6 +141,10 @@ is no origin fallback.
141
141
  307/308 cannot turn quote into call. There is no automatic quote-to-call sequence and no
142
142
  retry.
143
143
 
144
+ HTTP requests default to a 600-second (10-minute) timeout per attempt, matching
145
+ the Router's default downstream request budget. Explicit shorter timeouts,
146
+ including 10 seconds for public catalog reads, still apply.
147
+
144
148
  ## API Catalog
145
149
 
146
150
  `api list` and `api show` are the supported read-only catalog. They browse
@@ -163,6 +167,13 @@ A provider **id is not always its URL slug** — `brave-search` serves
163
167
  `/apis/v1/brave/...`, and `api show` prints the catalog path. The catalog
164
168
  reports every method as `GET`; treat that as advisory.
165
169
 
170
+ Prices with `type: metered` display as `usage-based` (billing depends on usage),
171
+ even when the catalog returns `normal: 0`. Details show `usage-based (cost varies)`.
172
+ Use `aisa quote` for a request-specific estimate; JSON keeps the original pricing metadata.
173
+ In `--json` output, metered providers and endpoints also include `pricing_note`
174
+ with quote guidance, including endpoints nested in provider details. The list
175
+ remains an array, and the original `pricing` fields are unchanged.
176
+
166
177
  The catalog is cached in `~/.aisa/cache` (override with `AISA_CACHE_DIR`). Pass
167
178
  `--refresh` to any command to bypass it, or `aisa cache clear`.
168
179
 
@@ -172,7 +183,7 @@ GPT, Claude, Gemini, DeepSeek, Kimi, GLM, Qwen and the rest behind one
172
183
  OpenAI-compatible endpoint.
173
184
 
174
185
  ```bash
175
- aisa chat "your message" --model gpt-4.1-mini
186
+ aisa chat "your message" --model deepseek-v4.1-flash
176
187
  aisa chat "explain this" --model claude-opus-4-6
177
188
  aisa chat "respond in JSON" --model gemini-2.5-pro --json
178
189
  echo "summarize this" | aisa chat # pipe support
@@ -340,7 +351,7 @@ aisa config reset
340
351
  ```
341
352
 
342
353
  Settings:
343
- - `defaultModel` — default model for `aisa chat` (default: `gpt-4.1-mini`)
354
+ - `defaultModel` — default model for `aisa chat` (default: `deepseek-v4.1-flash`). Existing saved model settings are preserved.
344
355
  - `baseUrl` — platform root; the LLM (`/v1`), integration (`/apis/v1`), and
345
356
  catalog bases are all derived from it
346
357
  - `routerUrl` — Tool Router origin (default `https://tools.aisa.one`,
package/dist/api.d.ts CHANGED
@@ -41,7 +41,7 @@ export interface RequestOptions {
41
41
  * completion reads rather than writes.
42
42
  */
43
43
  idempotent?: boolean;
44
- /** Overrides the default 30s budget for a slow endpoint. */
44
+ /** Overrides the default 600s per-attempt request budget. */
45
45
  timeoutMs?: number;
46
46
  }
47
47
  export declare function apiRequest<T = unknown>(accessToken: string, endpoint: string, options?: RequestOptions): Promise<ApiResponse<T>>;
package/dist/catalog.d.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  */
12
12
  export interface CatalogPricing {
13
13
  type: string;
14
- /** Dollars per request, as a float — not micros. */
14
+ /** Dollars per request, as a float — not micros. Metered prices may use 0 as a placeholder. */
15
15
  normal: number;
16
16
  }
17
17
  export interface CatalogProvider {
@@ -66,8 +66,9 @@ export declare function toRunPath(path: string): string;
66
66
  */
67
67
  export declare function runSlugOf(detail: CatalogDetail): string | undefined;
68
68
  /**
69
- * Format a per-request price. Real values span $0.000001 to $0.08, so a fixed
69
+ * Format catalog pricing, keeping metered billing distinct from a free request.
70
+ * Fixed prices span $0.000001 to $0.08, so a fixed
70
71
  * number of decimals either rounds the cheap endpoints to $0.00 or pads the
71
72
  * rest with noise — keep two significant digits instead.
72
73
  */
73
- export declare function formatPrice(usd?: number): string;
74
+ export declare function formatPrice(pricing?: CatalogPricing): string;
package/dist/catalog.js CHANGED
@@ -62,11 +62,15 @@ export function runSlugOf(detail) {
62
62
  return first ? toRunPath(first.path).split("/")[0] : undefined;
63
63
  }
64
64
  /**
65
- * Format a per-request price. Real values span $0.000001 to $0.08, so a fixed
65
+ * Format catalog pricing, keeping metered billing distinct from a free request.
66
+ * Fixed prices span $0.000001 to $0.08, so a fixed
66
67
  * number of decimals either rounds the cheap endpoints to $0.00 or pads the
67
68
  * rest with noise — keep two significant digits instead.
68
69
  */
69
- export function formatPrice(usd) {
70
+ export function formatPrice(pricing) {
71
+ if (pricing?.type === "metered")
72
+ return "usage-based";
73
+ const usd = pricing?.normal;
70
74
  if (usd == null)
71
75
  return "—";
72
76
  if (usd === 0)
@@ -4,6 +4,21 @@ import { error, formatJson, hint, table, truncate } from "../utils/display.js";
4
4
  import { API_CATEGORIES, categoryOf } from "../constants.js";
5
5
  import { getProviders, getProviderDetail, getHealth, flatEndpoints, toRunPath, runSlugOf, formatPrice, } from "../catalog.js";
6
6
  const DEFAULT_ENDPOINT_LIMIT = 40;
7
+ const CATALOG_HINT = "Catalog paths and prices are browsing metadata. Use aisa schema for parameters and aisa quote for a request-specific estimate.";
8
+ const USAGE_BASED_PRICING_NOTE = "Usage-based billing. Use aisa quote for a request-specific estimate.";
9
+ function withPricingNote(item) {
10
+ return item.pricing?.type === "metered"
11
+ ? { ...item, pricing_note: USAGE_BASED_PRICING_NOTE }
12
+ : item;
13
+ }
14
+ function pricingDescription(pricing, from = false) {
15
+ const price = formatPrice(pricing);
16
+ if (pricing?.type === "metered")
17
+ return `${price} (cost varies)`;
18
+ if (pricing?.normal == null)
19
+ return price;
20
+ return `${from && pricing.normal > 0 ? "from " : ""}${price} per request`;
21
+ }
7
22
  function statusBadge(status) {
8
23
  switch (status) {
9
24
  case "healthy":
@@ -41,13 +56,13 @@ export async function apiListAction(options) {
41
56
  }
42
57
  if (options.json) {
43
58
  console.log(formatJson(providers.map((p) => ({
44
- ...p,
59
+ ...withPricingNote(p),
45
60
  category: categoryOf(p.id),
46
61
  ...(options.health ? { health: healthById.get(p.id)?.status } : {}),
47
62
  }))));
48
63
  return;
49
64
  }
50
- const headers = ["API", "CATEGORY", "ENDPOINTS", "FROM", "UPDATED"];
65
+ const headers = ["API", "CATEGORY", "ENDPOINTS", "PRICING", "UPDATED"];
51
66
  if (options.health)
52
67
  headers.push("STATUS");
53
68
  const rows = providers.map((p) => {
@@ -55,7 +70,9 @@ export async function apiListAction(options) {
55
70
  p.id,
56
71
  categoryOf(p.id),
57
72
  String(p.endpoint_count),
58
- formatPrice(p.pricing?.normal),
73
+ p.pricing?.type !== "metered" && p.pricing?.normal != null && p.pricing.normal > 0
74
+ ? `from ${formatPrice(p.pricing)}`
75
+ : formatPrice(p.pricing),
59
76
  shortDate(p.updated_at),
60
77
  ];
61
78
  if (options.health)
@@ -68,7 +85,7 @@ export async function apiListAction(options) {
68
85
  console.log();
69
86
  console.log(chalk.gray(` ${providers.length} APIs · ${total} endpoints`));
70
87
  hint("Details: aisa api show <api>");
71
- hint("Catalog paths and prices are browsing metadata, not a substitute for aisa schema or aisa quote.");
88
+ hint(CATALOG_HINT);
72
89
  }
73
90
  /** Resolve a provider by id, or by the URL slug its endpoints are served under. */
74
91
  async function findProvider(idOrSlug, refresh) {
@@ -93,13 +110,13 @@ function printEndpointDetail(detail, endpoint) {
93
110
  console.log(` ${endpoint.description}`);
94
111
  console.log(`\n Path: ${endpoint.path}`);
95
112
  console.log(` Provider: ${detail.id}`);
96
- console.log(` Price: ${formatPrice(endpoint.pricing?.normal)} per request`);
113
+ console.log(` Pricing: ${pricingDescription(endpoint.pricing)}`);
97
114
  const params = [...runPath.matchAll(/\{([^}]+)\}/g)].map((m) => m[1]);
98
115
  if (params.length > 0) {
99
116
  console.log(` Path params: ${params.join(", ")}`);
100
117
  }
101
118
  console.log();
102
- hint("Catalog paths and prices are browsing metadata, not a substitute for aisa schema or aisa quote.");
119
+ hint(CATALOG_HINT);
103
120
  }
104
121
  export async function apiShowAction(idOrSlug, path, options = {}) {
105
122
  const spinner = ora(`Loading ${idOrSlug}...`).start();
@@ -140,21 +157,30 @@ export async function apiShowAction(idOrSlug, path, options = {}) {
140
157
  return;
141
158
  }
142
159
  if (options.json) {
143
- console.log(formatJson(matches[0]));
160
+ console.log(formatJson(withPricingNote(matches[0])));
144
161
  return;
145
162
  }
146
163
  printEndpointDetail(detail, matches[0]);
147
164
  return;
148
165
  }
149
166
  if (options.json) {
150
- console.log(formatJson(detail));
167
+ console.log(formatJson({
168
+ ...withPricingNote(detail),
169
+ ...(detail.endpoint_groups ? {
170
+ endpoint_groups: detail.endpoint_groups.map((group) => ({
171
+ ...group,
172
+ ...(group.endpoints ? { endpoints: group.endpoints.map(withPricingNote) } : {}),
173
+ })),
174
+ } : {}),
175
+ }));
151
176
  return;
152
177
  }
153
178
  const health = options.health
154
179
  ? (await getHealth({ refresh: options.refresh })).find((h) => h.id === detail.id)
155
180
  : undefined;
156
181
  console.log(`\n ${chalk.cyan.bold(detail.id)} ${chalk.gray(`(${categoryOf(detail.id)})`)}`);
157
- console.log(` ${detail.endpoint_count} endpoints · from ${formatPrice(detail.pricing?.normal)} per request`);
182
+ console.log(` ${detail.endpoint_count} endpoints`);
183
+ console.log(` Pricing: ${pricingDescription(detail.pricing, true)}`);
158
184
  console.log(` Updated ${shortDate(detail.updated_at)}`);
159
185
  if (health) {
160
186
  // Health is tracked per provider, not per endpoint — the per-endpoint
@@ -185,6 +211,6 @@ export async function apiShowAction(idOrSlug, path, options = {}) {
185
211
  if (runSlugOf(detail)) {
186
212
  console.log();
187
213
  hint(`Detail: aisa api show ${detail.id} <path>`);
188
- hint("Catalog paths and prices are browsing metadata, not a substitute for aisa schema or aisa quote.");
214
+ hint(CATALOG_HINT);
189
215
  }
190
216
  }
@@ -4,6 +4,7 @@ import { requireAccessToken, getConfig } from "../config.js";
4
4
  import { apiRequest, apiRequestRaw } from "../api.js";
5
5
  import { error } from "../utils/display.js";
6
6
  import { handleSSEStream } from "../utils/streaming.js";
7
+ import { DEFAULT_CHAT_MODEL } from "../constants.js";
7
8
  export async function chatAction(message, options) {
8
9
  const key = await requireAccessToken();
9
10
  // Read from stdin if no message provided
@@ -23,7 +24,7 @@ export async function chatAction(message, options) {
23
24
  error("Empty message");
24
25
  process.exit(1);
25
26
  }
26
- const model = options.model || getConfig("defaultModel") || "gpt-4.1-mini";
27
+ const model = options.model || getConfig("defaultModel") || DEFAULT_CHAT_MODEL;
27
28
  const stream = options.stream !== false; // default true
28
29
  const messages = [];
29
30
  if (options.system) {
@@ -4,7 +4,7 @@ import { existsSync, mkdirSync, writeFileSync, readFileSync } from "node:fs";
4
4
  import { join, resolve } from "node:path";
5
5
  import { error, success, hint, truncate } from "../utils/display.js";
6
6
  import { expandHome, ensureDir, writeSkillFiles, removeDir, detectAgents } from "../utils/file.js";
7
- import { AGENT_DIRS } from "../constants.js";
7
+ import { AGENT_DIRS, DEFAULT_CHAT_MODEL } from "../constants.js";
8
8
  import { SKILLS_REPO, getSkillIndex, listSkills, resolveSlug, leafName, fetchSkillFiles, fetchSkillMarkdown, parseSkillFrontmatter, } from "../skills-registry.js";
9
9
  // --- Skill Templates (for init) ---
10
10
  // Domain labels may stay; runnable steps use retained commands only.
@@ -74,7 +74,7 @@ export AISA_API_KEY=sk-your-key
74
74
  ## Chat Completion
75
75
 
76
76
  \`\`\`bash
77
- aisa chat "Your question here" --model gpt-4.1-mini
77
+ aisa chat "Your question here" --model ${DEFAULT_CHAT_MODEL}
78
78
  \`\`\`
79
79
 
80
80
  ## Streaming
package/dist/config.js CHANGED
@@ -5,7 +5,7 @@ import { join } from "node:path";
5
5
  import lockfile from "proper-lockfile";
6
6
  import { createHash, randomUUID } from "node:crypto";
7
7
  import { httpFetch } from "./utils/http.js";
8
- import { AUTH_SERVER, MISSING_API_KEY_GUIDANCE, ENV_VAR_NAME } from "./constants.js";
8
+ import { AUTH_SERVER, MISSING_API_KEY_GUIDANCE, ENV_VAR_NAME, DEFAULT_CHAT_MODEL } from "./constants.js";
9
9
  // tokens.json is authoritative; conf is a write-only compatibility mirror.
10
10
  const aisaDir = () => join(homedir(), ".aisa");
11
11
  const keyFile = () => join(aisaDir(), "key");
@@ -118,7 +118,7 @@ const config = new Conf({
118
118
  schema: {
119
119
  tokens: { type: "object", default: {} },
120
120
  apiKey: { type: "string", default: "" },
121
- defaultModel: { type: "string", default: "gpt-4.1-mini" },
121
+ defaultModel: { type: "string", default: DEFAULT_CHAT_MODEL },
122
122
  baseUrl: { type: "string", default: "https://api.aisa.one/v1" },
123
123
  routerUrl: { type: "string", default: "" },
124
124
  outputFormat: { type: "string", default: "text" },
@@ -1,4 +1,6 @@
1
- export declare const VERSION = "0.6.2";
1
+ export declare const VERSION = "0.6.4";
2
+ /** Default for chat when no model is configured or supplied explicitly. */
3
+ export declare const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
2
4
  /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
3
5
  export declare const BASE_URL = "https://api.aisa.one";
4
6
  export declare const ENV_VAR_NAME = "AISA_API_KEY";
package/dist/constants.js CHANGED
@@ -1,4 +1,6 @@
1
- export const VERSION = "0.6.2";
1
+ export const VERSION = "0.6.4";
2
+ /** Default for chat when no model is configured or supplied explicitly. */
3
+ export const DEFAULT_CHAT_MODEL = "deepseek-v4.1-flash";
2
4
  /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
3
5
  export const BASE_URL = "https://api.aisa.one";
4
6
  export const ENV_VAR_NAME = "AISA_API_KEY";
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command, Option } from "commander";
3
- import { VERSION } from "./constants.js";
3
+ import { VERSION, DEFAULT_CHAT_MODEL } from "./constants.js";
4
4
  import { CliError } from "./cli-error.js";
5
5
  // Auth
6
6
  import { loginAction, logoutAction, whoamiAction } from "./commands/auth.js";
@@ -152,7 +152,7 @@ api
152
152
  .description("List available APIs")
153
153
  .option("--category <cat>", "Filter by category (client-side grouping): finance, search, social, productivity, other")
154
154
  .option("--health", "Include provider health status")
155
- .option("--json", "Output raw JSON")
155
+ .option("--json", "Output catalog JSON with pricing guidance")
156
156
  .option("--refresh", "Bypass the cached catalog")
157
157
  .action(wrap(apiListAction));
158
158
  api
@@ -161,14 +161,14 @@ api
161
161
  .option("--all", "Show every endpoint instead of the first 40")
162
162
  .option("--group", "Group by the provider's raw endpoint groups")
163
163
  .option("--health", "Include provider health status")
164
- .option("--json", "Output raw JSON")
164
+ .option("--json", "Output catalog JSON with pricing guidance")
165
165
  .option("--refresh", "Bypass the cached catalog")
166
166
  .action(wrap(apiShowAction));
167
167
  // ── Chat (LLM Gateway) ──
168
168
  program
169
169
  .command("chat [message]")
170
170
  .description("Chat with AI models via the AIsa gateway")
171
- .option("--model <model>", "Model ID (default: gpt-4.1-mini)")
171
+ .option("--model <model>", `Model ID (default: ${DEFAULT_CHAT_MODEL})`)
172
172
  .option("--system <prompt>", "System prompt")
173
173
  .option("--no-stream", "Disable streaming")
174
174
  .option("--json", "Output raw JSON response")
@@ -33,8 +33,8 @@
33
33
  export declare const MAX_ATTEMPTS = 3;
34
34
  /** Catalog, health and other /info reads — small payloads from a CDN edge. */
35
35
  export declare const INFO_TIMEOUT_MS = 10000;
36
- /** A normal authenticated API call. */
37
- export declare const DEFAULT_TIMEOUT_MS = 30000;
36
+ /** Per-attempt API budget, aligned with Router AISA_HTTP_TIMEOUT (600s). */
37
+ export declare const DEFAULT_TIMEOUT_MS = 600000;
38
38
  export declare const USER_AGENT = "aisa-cli";
39
39
  export interface HttpOptions extends RequestInit {
40
40
  timeoutMs?: number;
@@ -33,8 +33,8 @@
33
33
  export const MAX_ATTEMPTS = 3;
34
34
  /** Catalog, health and other /info reads — small payloads from a CDN edge. */
35
35
  export const INFO_TIMEOUT_MS = 10_000;
36
- /** A normal authenticated API call. */
37
- export const DEFAULT_TIMEOUT_MS = 30_000;
36
+ /** Per-attempt API budget, aligned with Router AISA_HTTP_TIMEOUT (600s). */
37
+ export const DEFAULT_TIMEOUT_MS = 600_000;
38
38
  export const USER_AGENT = "aisa-cli";
39
39
  const BASE_BACKOFF_MS = 300;
40
40
  /** Agents fan out many calls at once; identical backoff would resynchronise
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aisa-one/cli",
3
- "version": "0.6.2",
3
+ "version": "0.6.4",
4
4
  "description": "CLI for the AIsa unified AI infrastructure platform - one API key for 80+ LLMs and 900+ endpoints across finance, search, social, and video APIs",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",