kiosapi 0.1.5 → 0.1.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/dist/agent/run.js CHANGED
@@ -124,7 +124,7 @@ export async function runTurn(s, userText) {
124
124
  const calls = reply.tool_calls ?? [];
125
125
  if (calls.length === 0) {
126
126
  if (step === 0) {
127
- console.log(dim('(Model tidak memakai tool — pastikan model mendukung function calling, mis. /model anthropic/claude-sonnet-4-6.)'));
127
+ console.log(dim('(Model tidak memakai tool — pilih model ber-🔧 untuk agen, mis. /model deepseek/deepseek-v4-flash.)'));
128
128
  }
129
129
  return lastText; // final text answer
130
130
  }
package/dist/api.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { loadConfig } from './config.js';
2
- import { dim } from './ui.js';
2
+ import { dim, sleep } from './ui.js';
3
3
  /** Turn an upstream HTTP status into an actionable Indonesian message. */
4
4
  function humanizeError(status) {
5
5
  if (status === 401)
@@ -61,22 +61,45 @@ export async function resolveModel(flag) {
61
61
  process.stderr.write(`${dim(`(model otomatis: ${pick.id} — atur tetap dengan: kiosapi setel model <id>)`)}\n`);
62
62
  return pick.id;
63
63
  }
64
- /** Authenticated request to the gateway with a humanized error on failure. */
64
+ /** Prefer the gateway's own (localized) error message; fall back to a status-based one. */
65
+ async function gatewayError(res) {
66
+ try {
67
+ const body = (await res.json());
68
+ if (body?.error?.message)
69
+ return body.error.message;
70
+ }
71
+ catch {
72
+ // non-JSON body
73
+ }
74
+ return humanizeError(res.status);
75
+ }
76
+ const RETRY_BACKOFF_MS = [5000, 10000, 20000];
77
+ /**
78
+ * Authenticated request to the gateway. Retries 429 (rate limit) with a silent backoff — agent/`tim`
79
+ * runs burst many requests and easily hit the per-minute cap, so a brief wait + retry keeps them
80
+ * going instead of failing. On other errors, surfaces the gateway's own message.
81
+ */
65
82
  async function authedFetch(path, init) {
66
- const { baseUrl, apiKey } = loadConfig();
67
- if (!apiKey)
68
- throw new Error('Belum masuk. Jalankan: kiosapi masuk');
69
- const res = await fetch(`${baseUrl}${path}`, {
70
- ...init,
71
- headers: {
72
- Authorization: `Bearer ${apiKey}`,
73
- 'Content-Type': 'application/json',
74
- ...init?.headers,
75
- },
76
- });
77
- if (!res.ok)
78
- throw new Error(humanizeError(res.status));
79
- return res;
83
+ for (let attempt = 0;; attempt++) {
84
+ const { baseUrl, apiKey } = loadConfig();
85
+ if (!apiKey)
86
+ throw new Error('Belum masuk. Jalankan: kiosapi masuk');
87
+ const res = await fetch(`${baseUrl}${path}`, {
88
+ ...init,
89
+ headers: {
90
+ Authorization: `Bearer ${apiKey}`,
91
+ 'Content-Type': 'application/json',
92
+ ...init?.headers,
93
+ },
94
+ });
95
+ if (res.ok)
96
+ return res;
97
+ if (res.status === 429 && attempt < RETRY_BACKOFF_MS.length) {
98
+ await sleep(RETRY_BACKOFF_MS[attempt] ?? 20000);
99
+ continue;
100
+ }
101
+ throw new Error(await gatewayError(res));
102
+ }
80
103
  }
81
104
  /** GET /v1/saldo — own balance summary. */
82
105
  export async function fetchSaldo() {
@@ -156,7 +179,11 @@ export async function chatComplete(model, messages, tools, onText) {
156
179
  }
157
180
  const tool_calls = [...calls.values()]
158
181
  .filter((c) => c.name)
159
- .map((c) => ({ id: c.id, function: { name: c.name, arguments: c.args } }));
182
+ .map((c) => ({
183
+ id: c.id,
184
+ type: 'function',
185
+ function: { name: c.name, arguments: c.args },
186
+ }));
160
187
  return { content: content || null, tool_calls: tool_calls.length > 0 ? tool_calls : undefined };
161
188
  }
162
189
  /** Parse an OpenAI SSE stream, yielding content deltas. */
package/dist/commands.js CHANGED
@@ -136,7 +136,7 @@ export async function cmdModel(args) {
136
136
  /** Warn (best-effort) if the chosen model likely can't drive the agent's tools. */
137
137
  export async function warnIfNoTools(model) {
138
138
  if (!(await modelSupportsTools(model))) {
139
- console.error(yellow(`⚠ Model "${model}" mungkin tak mendukung tool calling — agen bisa tak bekerja. Pilih model 🔧 (lihat: kiosapi model --tools), mis. anthropic/claude-sonnet-4-6.`));
139
+ console.error(yellow(`⚠ Model "${model}" tak mendukung tool calling via Kiosapi — agen tak bekerja. Pilih model 🔧 (lihat: kiosapi model --tools), mis. deepseek/deepseek-v4-flash.`));
140
140
  }
141
141
  }
142
142
  /** tanya — one-shot streaming question (also reads piped stdin as context). */
@@ -436,10 +436,9 @@ export async function cmdTim(args) {
436
436
  /** saldo — show own balance, bonus tokens, and month-to-date spend. */
437
437
  export async function cmdSaldo() {
438
438
  const s = await fetchSaldo();
439
- console.log(`${bold('Saldo')} : ${green(rupiah(s.balance_rupiah))}`);
440
- console.log(`Bonus token : ${idn(s.bonus_tokens)}`);
439
+ console.log(`${bold('Saldo')} : ${green(rupiah(s.balance_rupiah))}`);
441
440
  const cap = s.monthly_cap_rupiah != null ? ` / batas ${rupiah(s.monthly_cap_rupiah)}` : '';
442
- console.log(`Bulan ini : ${rupiah(s.month_spend_rupiah)}${dim(cap)}`);
441
+ console.log(`Bulan ini : ${rupiah(s.month_spend_rupiah)}${dim(cap)}`);
443
442
  }
444
443
  /** pakai — usage summary over the last N days (default 30). */
445
444
  export async function cmdPakai(args) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiosapi",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "type": "module",
5
5
  "description": "CLI Kiosapi.id berbahasa Indonesia — bangun aplikasimu pakai API key Kiosapi (agen + multimodal).",
6
6
  "keywords": [