@argosvix/sdk 0.1.0 → 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/CHANGELOG.md +92 -0
- package/README.md +54 -49
- package/dist/recorder.d.ts +12 -0
- package/dist/recorder.d.ts.map +1 -1
- package/dist/recorder.js +41 -1
- package/dist/recorder.js.map +1 -1
- package/package.json +3 -7
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `@argosvix/sdk` are documented in this file.
|
|
4
|
+
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
5
|
+
and the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [0.1.2] - 2026-05-22
|
|
8
|
+
|
|
9
|
+
Documentation-only release that aligns the npm README with global SaaS norms.
|
|
10
|
+
|
|
11
|
+
### Changed
|
|
12
|
+
- README is now fully English. The prior version mixed Japanese and English in
|
|
13
|
+
the same sections, which is unusual for a globally distributed npm package
|
|
14
|
+
and weakened the first-impression signal on the npm registry page. Japanese
|
|
15
|
+
speakers can read the same content (and more) at https://argosvix.com which
|
|
16
|
+
ships JA / EN locales.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- Listed the new `examples/workers-anthropic/` integration alongside the
|
|
20
|
+
existing Next.js / Express / Lambda examples.
|
|
21
|
+
|
|
22
|
+
### Notes
|
|
23
|
+
- No SDK code changes. The compiled `dist/` output is byte-identical to
|
|
24
|
+
v0.1.1 except for the bundled README inside the tarball.
|
|
25
|
+
|
|
26
|
+
## [0.1.1] - 2026-05-21
|
|
27
|
+
|
|
28
|
+
Patch release that hardens short-lived runtime delivery and matches the SDK's
|
|
29
|
+
default endpoint to the live backend.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
- **Workers / Lambda fire-and-forget loss (HIGH).** When `bufferMaxSize` was
|
|
33
|
+
reached, `record()` started a background `flush()` whose `fetch` could be
|
|
34
|
+
killed by the runtime before completing. `flushClient()` now waits behind
|
|
35
|
+
any in-flight flush via an internal `inFlightFlush` promise, so records
|
|
36
|
+
buffered before the handler returned are guaranteed to reach the backend
|
|
37
|
+
in order.
|
|
38
|
+
- **Edge runtime crash on `process.env` (HIGH).** `record()` no longer assumes
|
|
39
|
+
a Node `process` global exists; environments without it (Cloudflare Workers
|
|
40
|
+
in some modes, Vercel Edge) used to throw and break the wrapped LLM call.
|
|
41
|
+
- **Default endpoint corrected to `https://ingest.argosvix.com/v1/ingest`.**
|
|
42
|
+
The previous default pointed to a non-existent subdomain
|
|
43
|
+
(`api.argosvix.com`), which would have failed for any user who omitted an
|
|
44
|
+
explicit `endpoint` in their `ArgosvixConfig`.
|
|
45
|
+
|
|
46
|
+
### Added
|
|
47
|
+
- Regression tests for the two `Recorder` fixes above (concurrent flush
|
|
48
|
+
serialization, missing `process` global).
|
|
49
|
+
|
|
50
|
+
### Documentation
|
|
51
|
+
- Source comments rewritten to English ahead of wider distribution.
|
|
52
|
+
|
|
53
|
+
## [0.1.0] - 2026-05-21
|
|
54
|
+
|
|
55
|
+
Initial public release on npm under the `alpha` dist-tag.
|
|
56
|
+
|
|
57
|
+
### Added
|
|
58
|
+
- `wrap(client, config?)`: transparent observability wrapper for AI provider
|
|
59
|
+
SDK clients. Supported targets:
|
|
60
|
+
- OpenAI `chat.completions.create` (sync + streaming) and `responses.create`
|
|
61
|
+
(sync; streaming is deferred to a later release).
|
|
62
|
+
- Anthropic `messages.create` (sync + streaming, with `message_start` /
|
|
63
|
+
`message_delta` accumulation).
|
|
64
|
+
- Mistral `chat.complete` and `chat.stream`.
|
|
65
|
+
- Gemini legacy SDK (`@google/generative-ai`) `getGenerativeModel(...)`
|
|
66
|
+
plus `generateContent` and `generateContentStream`.
|
|
67
|
+
- Gemini current SDK (`@google/genai`) `models.generateContent` and
|
|
68
|
+
`models.generateContentStream`.
|
|
69
|
+
- `getRecorder(client)`: retrieve the per-client `Recorder` instance.
|
|
70
|
+
- `flushClient(client)`: short-lived runtime helper that resolves only after
|
|
71
|
+
the buffer is delivered to the backend.
|
|
72
|
+
- `Recorder` class with `record()`, `flush()`, retry on 5xx/network with
|
|
73
|
+
exponential-ish backoff, and per-instance buffer isolation.
|
|
74
|
+
- `calculateCost(provider, model, prompt, completion)` and the public
|
|
75
|
+
`PRICING` table covering 2026-05 OpenAI / Anthropic / Gemini / Mistral
|
|
76
|
+
prices, with prefix matching for version-suffixed model IDs.
|
|
77
|
+
- TypeScript types: `Provider`, `ArgosvixConfig`, `LlmCallRecord`,
|
|
78
|
+
`PricingEntry`.
|
|
79
|
+
- Idempotency: wrapping the same client twice is a no-op (`WeakMap` for
|
|
80
|
+
clients, `WeakSet` for Gemini model instances).
|
|
81
|
+
|
|
82
|
+
### Notes
|
|
83
|
+
- The SDK does **not** record prompt or completion bodies. Only token counts,
|
|
84
|
+
cost, latency, tags, error metadata, and a small request-meta overview are
|
|
85
|
+
sent to the backend.
|
|
86
|
+
- `peerDependencies` for every provider SDK are marked optional — install
|
|
87
|
+
only the ones you actually use.
|
|
88
|
+
- License: MIT.
|
|
89
|
+
|
|
90
|
+
[0.1.2]: https://www.npmjs.com/package/@argosvix/sdk/v/0.1.2
|
|
91
|
+
[0.1.1]: https://www.npmjs.com/package/@argosvix/sdk/v/0.1.1
|
|
92
|
+
[0.1.0]: https://www.npmjs.com/package/@argosvix/sdk/v/0.1.0
|
package/README.md
CHANGED
|
@@ -1,38 +1,42 @@
|
|
|
1
1
|
# @argosvix/sdk
|
|
2
2
|
|
|
3
|
-
Transparent observability wrapper for AI provider SDKs. Wrap a single line of code and get cost
|
|
3
|
+
Transparent observability wrapper for AI provider SDKs. Wrap a single line of code and get cost, latency, token, and error records for every LLM call across OpenAI, Anthropic, Gemini, and Mistral.
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> 🟢 **Alpha released** — backend ingest (`ingest.argosvix.com`) and dashboard (`dashboard.argosvix.com`) are live. Published on npm as `@argosvix/sdk@alpha`. We operate as a Free-only plan during the current beta phase; the entire sign-up to API-key flow runs in the browser. See [`CHANGELOG.md`](./CHANGELOG.md) for the full change log.
|
|
6
6
|
>
|
|
7
|
-
>
|
|
8
|
-
> -
|
|
9
|
-
> - **wrap
|
|
10
|
-
> - **
|
|
7
|
+
> Design principles:
|
|
8
|
+
> - **No end-user PII is sent.** Prompt and completion bodies are never recorded; only token counts, cost, latency, and error codes leave your process.
|
|
9
|
+
> - **Idempotent wrap.** Wrapping the same client twice is a no-op; we track instances via WeakMap / WeakSet.
|
|
10
|
+
> - **No global monkey-patching.** Only the client argument you pass in is mutated; the global namespace is untouched.
|
|
11
11
|
|
|
12
12
|
## Supported providers
|
|
13
13
|
|
|
14
|
-
|
|
|
14
|
+
| Provider | Hook | Streaming | Notes |
|
|
15
15
|
|---|---|---|---|
|
|
16
16
|
| **OpenAI** chat.completions | ✅ | ✅ | `chat.completions.create` |
|
|
17
|
-
| **OpenAI** responses | ✅ | warn + skip(
|
|
18
|
-
| **Anthropic** | ✅ | ✅ | `messages.create`(`message_start` + `message_delta`
|
|
17
|
+
| **OpenAI** responses | ✅ | warn + skip (planned) | `responses.create` |
|
|
18
|
+
| **Anthropic** | ✅ | ✅ | `messages.create` (accumulates `message_start` + `message_delta`) |
|
|
19
19
|
| **Mistral** | ✅ | ✅ | `chat.complete` + `chat.stream` |
|
|
20
|
-
| **Gemini legacy**(`@google/generative-ai`)| ✅ | ✅ | `getGenerativeModel({...}).generateContent` / `generateContentStream` |
|
|
21
|
-
| **Gemini current**(`@google/genai`)| ✅ | ✅ | `client.models.generateContent` / `generateContentStream` |
|
|
20
|
+
| **Gemini legacy** (`@google/generative-ai`) | ✅ | ✅ | `getGenerativeModel({...}).generateContent` / `generateContentStream` |
|
|
21
|
+
| **Gemini current** (`@google/genai`) | ✅ | ✅ | `client.models.generateContent` / `generateContentStream` |
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
# alpha 段階 (= 公開後)
|
|
27
26
|
npm install @argosvix/sdk@alpha openai
|
|
27
|
+
# Also install the SDKs for any other providers you use (Anthropic, Gemini, Mistral).
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
### Obtain an API key
|
|
31
|
+
|
|
32
|
+
1. Sign up at <https://dashboard.argosvix.com/en/signup> with an email address and password.
|
|
33
|
+
2. Open the verification link sent to your inbox.
|
|
34
|
+
3. The verification screen displays your API key (`argosvix_live_…`) **once**. Copy and store it safely — it cannot be retrieved later (rotation will be available in a future release).
|
|
31
35
|
|
|
32
36
|
```bash
|
|
33
37
|
export ARGOSVIX_API_KEY=argosvix_live_...
|
|
34
|
-
#
|
|
35
|
-
#
|
|
38
|
+
# Default ingest endpoint = https://ingest.argosvix.com
|
|
39
|
+
# Override with ARGOSVIX_API_BASE if you self-host the backend.
|
|
36
40
|
```
|
|
37
41
|
|
|
38
42
|
## Quick start
|
|
@@ -46,24 +50,33 @@ const client = wrap(new OpenAI(), {
|
|
|
46
50
|
tags: { service: "support-bot", env: "production" },
|
|
47
51
|
});
|
|
48
52
|
|
|
49
|
-
// Use the wrapped client exactly like the original
|
|
53
|
+
// Use the wrapped client exactly like the original.
|
|
50
54
|
const response = await client.chat.completions.create({
|
|
51
55
|
model: "gpt-5.5",
|
|
52
56
|
messages: [{ role: "user", content: "Hello" }],
|
|
53
57
|
});
|
|
54
58
|
|
|
55
|
-
//
|
|
59
|
+
// Optional: graceful flush before process exit.
|
|
56
60
|
const recorder = getRecorder(client);
|
|
57
61
|
if (recorder) await recorder.flush();
|
|
58
62
|
```
|
|
59
63
|
|
|
60
|
-
|
|
64
|
+
Each call automatically records:
|
|
65
|
+
|
|
66
|
+
- Prompt and completion token counts (`promptTokens` / `completionTokens`, camelCase).
|
|
67
|
+
- USD cost, computed from the bundled per-provider pricing table. Resource-prefixed model names such as `models/gemini-2.0-flash` are normalized to their terminal model name.
|
|
68
|
+
- Latency in milliseconds.
|
|
69
|
+
- Streaming responses produce a record once the final usage chunk is observed (synced with consumer completion).
|
|
70
|
+
- Arbitrary tags (`tags: { service: "X", env: "prod" }`).
|
|
71
|
+
- Structured error details (`statusCode`, `code`, `type`, `retryAfter`).
|
|
61
72
|
|
|
62
|
-
|
|
73
|
+
**Not recorded:** prompt bodies, completion bodies, system messages, or tool-call argument bodies. Only the metadata required for aggregation is sent — no PII or confidential strings are stored.
|
|
63
74
|
|
|
64
|
-
|
|
75
|
+
## Short-lived runtimes (Cloudflare Workers / AWS Lambda / Vercel Edge)
|
|
65
76
|
|
|
66
|
-
|
|
77
|
+
These runtimes kill any outstanding fire-and-forget `fetch` the moment the handler returns. The SDK normally buffers records in memory and flushes them only when `bufferMaxSize` is reached (default 100), so a single request with a few LLM calls would lose its records on context exit.
|
|
78
|
+
|
|
79
|
+
Mitigation: await `flushClient(client)` in the handler's `finally` block.
|
|
67
80
|
|
|
68
81
|
```typescript
|
|
69
82
|
import Anthropic from "@anthropic-ai/sdk";
|
|
@@ -82,35 +95,25 @@ export default {
|
|
|
82
95
|
});
|
|
83
96
|
// ...
|
|
84
97
|
} finally {
|
|
85
|
-
await flushClient(client); //
|
|
98
|
+
await flushClient(client); // Required: guarantees backend delivery before exit.
|
|
86
99
|
}
|
|
87
100
|
},
|
|
88
101
|
};
|
|
89
102
|
```
|
|
90
103
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
- Prompt + completion token 数(camelCase の `promptTokens` / `completionTokens` で保持)
|
|
95
|
-
- USD コスト(provider 別 pricing テーブル + resource-prefixed model 名 `models/gemini-2.0-flash` 対応)
|
|
96
|
-
- 応答時間(ミリ秒)
|
|
97
|
-
- ストリーミング = 最終 chunk の usage を取得した時点で record(consumer 完了と同期)
|
|
98
|
-
- 任意タグ(`tags: { service: "X", env: "prod" }`)
|
|
99
|
-
- エラー詳細(`statusCode` / `code` / `type` / `retryAfter`)
|
|
100
|
-
|
|
101
|
-
**記録しない項目**: prompt 本文、 completion 本文、 system message、 tool call の引数本文。 集計に必要な metadata のみ送信し、 PII / 機密文字列を保管しない設計。
|
|
104
|
+
Long-running Node processes (Express, Next.js dev server, classic servers) do not need this — the buffer auto-flushes well before process exit.
|
|
102
105
|
|
|
103
106
|
## Composite client / explicit provider
|
|
104
107
|
|
|
105
|
-
|
|
108
|
+
When auto-detection is ambiguous (e.g. for composite or adapter clients), set `config.provider` explicitly:
|
|
106
109
|
|
|
107
110
|
```typescript
|
|
108
111
|
const client = wrap(myCompositeClient, { provider: "openai" });
|
|
109
112
|
```
|
|
110
113
|
|
|
111
|
-
## Tags +
|
|
114
|
+
## Tags + aggregation
|
|
112
115
|
|
|
113
|
-
|
|
116
|
+
Tags are persisted per record. The backend dashboard supports cross-dimension aggregation such as "cost trend for `service=support-bot`" (Phase C dashboard and beyond).
|
|
114
117
|
|
|
115
118
|
## Streaming
|
|
116
119
|
|
|
@@ -122,40 +125,42 @@ const stream = await client.chat.completions.create({
|
|
|
122
125
|
});
|
|
123
126
|
|
|
124
127
|
for await (const chunk of stream) {
|
|
125
|
-
//
|
|
128
|
+
// Consume as a normal AsyncIterable.
|
|
126
129
|
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
|
|
127
130
|
}
|
|
128
|
-
//
|
|
131
|
+
// A record is POSTed to the backend once the stream completes.
|
|
129
132
|
```
|
|
130
133
|
|
|
131
134
|
## Examples
|
|
132
135
|
|
|
133
|
-
[`examples/`](../../examples/)
|
|
134
|
-
|
|
135
|
-
- [`examples/
|
|
136
|
-
- [`examples/
|
|
136
|
+
The [`examples/`](../../examples/) directory contains minimum-viable integrations for four stacks:
|
|
137
|
+
|
|
138
|
+
- [`examples/nextjs-openai/`](../../examples/nextjs-openai/) — Next.js 14 App Router.
|
|
139
|
+
- [`examples/express-anthropic/`](../../examples/express-anthropic/) — Express with streaming and SIGTERM flush.
|
|
140
|
+
- [`examples/lambda-gemini/`](../../examples/lambda-gemini/) — AWS Lambda with `@google/genai` (note: container-reuse semantics).
|
|
141
|
+
- [`examples/workers-anthropic/`](../../examples/workers-anthropic/) — Cloudflare Workers with the `flushClient` pattern.
|
|
137
142
|
|
|
138
143
|
## API
|
|
139
144
|
|
|
140
145
|
### `wrap<T>(client: T, config?: ArgosvixConfig): T`
|
|
141
|
-
Transparently
|
|
146
|
+
Transparently wraps an AI SDK client. Returns the same client (mutated) so the call-site shape is unchanged.
|
|
142
147
|
|
|
143
148
|
### `getRecorder(client: object): Recorder | null`
|
|
144
|
-
|
|
149
|
+
Retrieves the `Recorder` instance associated with a wrapped client.
|
|
145
150
|
|
|
146
151
|
### `flushClient(client: object): Promise<void>`
|
|
147
|
-
Cloudflare Workers
|
|
152
|
+
Helper for short-lived runtimes (Cloudflare Workers, AWS Lambda, Vercel Edge). Awaiting this in a `finally` block explicitly flushes the SDK buffer and waits for backend delivery. Failures are logged via `console.error` only — never thrown — to avoid breaking the host application.
|
|
148
153
|
|
|
149
154
|
### `class Recorder`
|
|
150
155
|
- `record(record: LlmCallRecord): void`
|
|
151
|
-
- `flush(): Promise<LlmCallRecord[]>` —
|
|
156
|
+
- `flush(): Promise<LlmCallRecord[]>` — POSTs the buffer to the backend. Retries on 5xx and network errors; 4xx errors are not retried.
|
|
152
157
|
- `getBufferSize(): number`
|
|
153
158
|
|
|
154
159
|
### `calculateCost(provider, model, promptTokens, completionTokens): number`
|
|
155
|
-
Internal pricing calculator
|
|
160
|
+
Internal pricing calculator returning USD. Exported for unit tests and custom-pricing experimentation. Resource-prefixed model names (e.g. `models/gemini-2.0-flash`) are looked up by their terminal model name.
|
|
156
161
|
|
|
157
|
-
###
|
|
158
|
-
`Provider`
|
|
162
|
+
### Types
|
|
163
|
+
`Provider` · `ArgosvixConfig` · `LlmCallRecord` · `PricingEntry`
|
|
159
164
|
|
|
160
165
|
## License
|
|
161
166
|
|
package/dist/recorder.d.ts
CHANGED
|
@@ -10,6 +10,13 @@ import type { ArgosvixConfig, LlmCallRecord } from "./types.js";
|
|
|
10
10
|
export declare class Recorder {
|
|
11
11
|
private buffer;
|
|
12
12
|
private readonly config;
|
|
13
|
+
/**
|
|
14
|
+
* Tracks the most recently started flush so that callers can serialize behind it.
|
|
15
|
+
* A fire-and-forget `void this.flush()` from `record()` (triggered when the buffer
|
|
16
|
+
* fills) starts an in-flight POST that `flushClient()` must wait on; otherwise
|
|
17
|
+
* Workers / Lambda may return while that POST is still in flight, killing it.
|
|
18
|
+
*/
|
|
19
|
+
private inFlightFlush;
|
|
13
20
|
constructor(config?: ArgosvixConfig);
|
|
14
21
|
record(record: LlmCallRecord): void;
|
|
15
22
|
/**
|
|
@@ -19,8 +26,13 @@ export declare class Recorder {
|
|
|
19
26
|
* If all attempts fail the records are dropped and logged via console.error
|
|
20
27
|
* (durable persistence is intentionally out of scope for the MVP).
|
|
21
28
|
* Errors are never thrown — backend outages must not break the host application.
|
|
29
|
+
*
|
|
30
|
+
* Concurrent flush calls are serialized via `inFlightFlush`. An auto-flush
|
|
31
|
+
* triggered by `bufferMaxSize` and a subsequent explicit `flushClient()`
|
|
32
|
+
* both await the same promise instead of racing.
|
|
22
33
|
*/
|
|
23
34
|
flush(): Promise<LlmCallRecord[]>;
|
|
35
|
+
private doFlush;
|
|
24
36
|
getBufferSize(): number;
|
|
25
37
|
/**
|
|
26
38
|
* Test-only helper. Do not call from production code.
|
package/dist/recorder.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;
|
|
1
|
+
{"version":3,"file":"recorder.d.ts","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhE;;;;;;;GAOG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;IACxC;;;;;OAKG;IACH,OAAO,CAAC,aAAa,CAAyC;gBAElD,MAAM,GAAE,cAAmB;IAIvC,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI;IAuBnC;;;;;;;;;;;OAWG;IACG,KAAK,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;YAwBzB,OAAO;IA8DrB,aAAa,IAAI,MAAM;IAIvB;;;OAGG;IACH,iBAAiB,IAAI,IAAI;CAI1B"}
|
package/dist/recorder.js
CHANGED
|
@@ -9,6 +9,13 @@
|
|
|
9
9
|
export class Recorder {
|
|
10
10
|
buffer = [];
|
|
11
11
|
config;
|
|
12
|
+
/**
|
|
13
|
+
* Tracks the most recently started flush so that callers can serialize behind it.
|
|
14
|
+
* A fire-and-forget `void this.flush()` from `record()` (triggered when the buffer
|
|
15
|
+
* fills) starts an in-flight POST that `flushClient()` must wait on; otherwise
|
|
16
|
+
* Workers / Lambda may return while that POST is still in flight, killing it.
|
|
17
|
+
*/
|
|
18
|
+
inFlightFlush = null;
|
|
12
19
|
constructor(config = {}) {
|
|
13
20
|
this.config = config;
|
|
14
21
|
}
|
|
@@ -16,7 +23,13 @@ export class Recorder {
|
|
|
16
23
|
if (this.config.disabled)
|
|
17
24
|
return;
|
|
18
25
|
this.buffer.push(record);
|
|
19
|
-
|
|
26
|
+
// Guard `process` access — some edge runtimes (Cloudflare Workers in
|
|
27
|
+
// certain modes, Vercel Edge) do not expose a Node `process` global, and
|
|
28
|
+
// an unguarded `process.env[...]` reference would throw and break the
|
|
29
|
+
// host LLM call we are wrapping.
|
|
30
|
+
if (typeof process !== "undefined" &&
|
|
31
|
+
process.env != null &&
|
|
32
|
+
process.env["ARGOSVIX_DEBUG"] === "1") {
|
|
20
33
|
// eslint-disable-next-line no-console
|
|
21
34
|
console.log("[argosvix]", JSON.stringify(record));
|
|
22
35
|
}
|
|
@@ -32,11 +45,37 @@ export class Recorder {
|
|
|
32
45
|
* If all attempts fail the records are dropped and logged via console.error
|
|
33
46
|
* (durable persistence is intentionally out of scope for the MVP).
|
|
34
47
|
* Errors are never thrown — backend outages must not break the host application.
|
|
48
|
+
*
|
|
49
|
+
* Concurrent flush calls are serialized via `inFlightFlush`. An auto-flush
|
|
50
|
+
* triggered by `bufferMaxSize` and a subsequent explicit `flushClient()`
|
|
51
|
+
* both await the same promise instead of racing.
|
|
35
52
|
*/
|
|
36
53
|
async flush() {
|
|
54
|
+
// Wait behind any in-flight flush so callers (e.g. flushClient in a Worker
|
|
55
|
+
// handler's `finally`) cannot return before earlier records reach the backend.
|
|
56
|
+
if (this.inFlightFlush) {
|
|
57
|
+
try {
|
|
58
|
+
await this.inFlightFlush;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
// Errors from the prior flush are already logged inside doFlush; swallow here.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
37
64
|
if (this.buffer.length === 0)
|
|
38
65
|
return [];
|
|
39
66
|
const records = this.buffer.splice(0);
|
|
67
|
+
const promise = this.doFlush(records);
|
|
68
|
+
this.inFlightFlush = promise;
|
|
69
|
+
try {
|
|
70
|
+
return await promise;
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
if (this.inFlightFlush === promise) {
|
|
74
|
+
this.inFlightFlush = null;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async doFlush(records) {
|
|
40
79
|
if (this.config.disabled || !this.config.apiKey) {
|
|
41
80
|
return records;
|
|
42
81
|
}
|
|
@@ -95,6 +134,7 @@ export class Recorder {
|
|
|
95
134
|
*/
|
|
96
135
|
__resetForTesting() {
|
|
97
136
|
this.buffer.splice(0);
|
|
137
|
+
this.inFlightFlush = null;
|
|
98
138
|
}
|
|
99
139
|
}
|
|
100
140
|
//# sourceMappingURL=recorder.js.map
|
package/dist/recorder.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,MAAM,OAAO,QAAQ;IACX,MAAM,GAAoB,EAAE,CAAC;IACpB,MAAM,CAAiB;
|
|
1
|
+
{"version":3,"file":"recorder.js","sourceRoot":"","sources":["../src/recorder.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@argosvix/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Drop-in observability wrapper for OpenAI, Anthropic, Gemini, Mistral SDK clients. One-line wrap() = cost / latency / quality records.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"argosvix",
|
|
@@ -18,12 +18,7 @@
|
|
|
18
18
|
"author": "jissocyu",
|
|
19
19
|
"homepage": "https://argosvix.com",
|
|
20
20
|
"bugs": {
|
|
21
|
-
"
|
|
22
|
-
},
|
|
23
|
-
"repository": {
|
|
24
|
-
"type": "git",
|
|
25
|
-
"url": "git+https://github.com/typing-game/Argosvix.git",
|
|
26
|
-
"directory": "packages/sdk"
|
|
21
|
+
"email": "hello@argosvix.com"
|
|
27
22
|
},
|
|
28
23
|
"type": "module",
|
|
29
24
|
"main": "./dist/index.js",
|
|
@@ -37,6 +32,7 @@
|
|
|
37
32
|
"files": [
|
|
38
33
|
"dist",
|
|
39
34
|
"README.md",
|
|
35
|
+
"CHANGELOG.md",
|
|
40
36
|
"LICENSE"
|
|
41
37
|
],
|
|
42
38
|
"engines": {
|