llm-messages 0.5.1 → 0.5.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 +119 -1
- package/README.md +79 -34
- package/ROADMAP.md +3 -3
- package/SECURITY.md +24 -0
- package/dist/index.cjs +643 -93
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -9
- package/dist/index.d.ts +11 -9
- package/dist/index.js +641 -92
- package/dist/index.js.map +1 -1
- package/docs/adoption-guide.md +7 -0
- package/docs/conformance-fixtures.md +113 -13
- package/examples/commonjs.cjs +34 -0
- package/examples/usage.mjs +19 -4
- package/package.json +8 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,122 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.5.2] - 2026-06-12
|
|
10
|
+
|
|
11
|
+
### Summary
|
|
12
|
+
|
|
13
|
+
- Added an offline conformance suite for OpenAI Chat Completions, OpenAI
|
|
14
|
+
Responses, Anthropic and Gemini edge cases around tool-call ids, arguments,
|
|
15
|
+
refusals and tool-result mapping.
|
|
16
|
+
- Strengthened the release path with one local validation command, package
|
|
17
|
+
dry-run checks, installed ESM/CommonJS/type smoke tests and a Node 18 consumer
|
|
18
|
+
smoke in CI.
|
|
19
|
+
- Documented the response-normalization helpers, stable warning-code export and
|
|
20
|
+
fixture workflow so users and maintainers can audit the supported portability
|
|
21
|
+
surface before publishing.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- Added an offline conformance fixture harness and committed fixtures for
|
|
26
|
+
OpenAI Chat Completions, OpenAI Responses, Anthropic and Gemini request and
|
|
27
|
+
response conversions.
|
|
28
|
+
- Covered deterministic id generation and reservation, duplicate provider ids,
|
|
29
|
+
malformed function names, invalid argument payloads, refusals, unsupported
|
|
30
|
+
OpenAI tool-call types, Anthropic `tool_result` mapping and Gemini
|
|
31
|
+
`functionResponse` matching.
|
|
32
|
+
- Documented direct response normalizers, stable warning codes, Gemini id/name
|
|
33
|
+
matching, the fixture contract and inventory, roadmap distinctions,
|
|
34
|
+
contributor validation commands and release staging review steps.
|
|
35
|
+
- Aligned the pull request checklist with the conformance fixture inventory
|
|
36
|
+
workflow so fixture changes are reviewed with their docs update.
|
|
37
|
+
- Added `npm run check`, `pack:check` and `examples:check`, then aligned CI and
|
|
38
|
+
release validation around format, typecheck, lint, tests, build, examples,
|
|
39
|
+
pack dry-run and package smoke checks.
|
|
40
|
+
- Added a CommonJS usage example and extended packaged examples to cover
|
|
41
|
+
response normalization and the `warningCodes` export.
|
|
42
|
+
- Strengthened package smoke testing to install the packed tarball, exercise
|
|
43
|
+
ESM/CommonJS/types, run bundled examples, verify intentional public files,
|
|
44
|
+
reject private source/test/script/config leaks, validate package metadata and
|
|
45
|
+
inspect source maps and audit packaged Markdown file and heading-anchor links.
|
|
46
|
+
- Added a fixture-backed self-test for the packaged Markdown link checker so the
|
|
47
|
+
smoke script verifies missing files, missing anchors and package-escaping links
|
|
48
|
+
before auditing the real tarball.
|
|
49
|
+
- Exported, froze and documented the `warningCodes` runtime list from the
|
|
50
|
+
package root so tests and consumers can validate warning-code values against
|
|
51
|
+
the public API.
|
|
52
|
+
- Tightened the conformance warning-code guard so stale public warning codes
|
|
53
|
+
fail tests if they are no longer emitted by the source.
|
|
54
|
+
|
|
55
|
+
### Fixed
|
|
56
|
+
|
|
57
|
+
- Drop Gemini `thought: true` (reasoning) response parts with a
|
|
58
|
+
`dropped-content` warning instead of mixing the model's reasoning text into
|
|
59
|
+
the canonical assistant content.
|
|
60
|
+
- Preserve OpenAI Chat Completions refusal text and refusal content parts when
|
|
61
|
+
assistant `content` is empty or array-shaped.
|
|
62
|
+
- Drop unsupported OpenAI Chat Completions `tool_calls[]` types with a
|
|
63
|
+
`dropped-content` warning instead of emitting malformed canonical function
|
|
64
|
+
calls.
|
|
65
|
+
- Warn and continue when OpenAI Chat Completions `tool_calls` payloads or
|
|
66
|
+
entries are malformed instead of silently skipping provider output.
|
|
67
|
+
- Normalize legacy OpenAI Chat Completions `message.function_call` responses
|
|
68
|
+
into canonical `tool_calls` with deterministic ids.
|
|
69
|
+
- Warn and fall back to empty canonical arguments when OpenAI Chat Completions,
|
|
70
|
+
OpenAI Responses, Anthropic or Gemini tool-call argument payloads are
|
|
71
|
+
malformed JSON, JSON non-objects or explicit non-object provider-native
|
|
72
|
+
values.
|
|
73
|
+
- Warn and fall back to empty canonical arguments when provider-native argument
|
|
74
|
+
objects cannot be JSON serialized.
|
|
75
|
+
- Preserve malformed response-level tool calls from OpenAI Chat Completions,
|
|
76
|
+
OpenAI Responses, Anthropic and Gemini by substituting the same stable
|
|
77
|
+
fallback function name used by conversation converters.
|
|
78
|
+
- Warn with `dropped-content` when OpenAI Chat Completions, OpenAI Responses,
|
|
79
|
+
Anthropic or Gemini response-level content parts are unsupported instead of
|
|
80
|
+
silently dropping provider output parts.
|
|
81
|
+
- Warn with `dropped-content` when OpenAI Chat Completions, OpenAI Responses,
|
|
82
|
+
Anthropic or Gemini response normalizers receive malformed top-level response
|
|
83
|
+
bodies.
|
|
84
|
+
- Warn with `dropped-content` when OpenAI Chat Completions, Anthropic or Gemini
|
|
85
|
+
response bodies omit or malform their primary output arrays instead of
|
|
86
|
+
silently returning an empty assistant message.
|
|
87
|
+
- Warn with `dropped-content` when OpenAI Chat Completions response choices omit
|
|
88
|
+
or malform their assistant `message` object instead of silently dropping the
|
|
89
|
+
choice payload.
|
|
90
|
+
- Warn with `dropped-content` when OpenAI Responses top-level `output[]` items
|
|
91
|
+
are malformed or unsupported instead of silently skipping provider output
|
|
92
|
+
items.
|
|
93
|
+
- Treat whitespace-only, OpenAI-incompatible and longer-than-64-character
|
|
94
|
+
provider function names as malformed before emitting canonical tool calls.
|
|
95
|
+
- Generate deterministic OpenAI tool-call ids for OpenAI Chat Completions,
|
|
96
|
+
OpenAI Responses, Anthropic and Gemini values that are omitted, empty or
|
|
97
|
+
non-string.
|
|
98
|
+
- Reserve provider-supplied tool-call ids before generating fallbacks, avoid
|
|
99
|
+
generated-id collisions and regenerate duplicate provider-supplied ids with a
|
|
100
|
+
`generated-id` warning.
|
|
101
|
+
- Preserve Gemini `functionResponse` behavior by preferring explicit ids,
|
|
102
|
+
warning on unmapped ids without consuming same-name pending calls, recovering
|
|
103
|
+
omitted or malformed names from id matches, ignoring non-string ids before
|
|
104
|
+
falling back by name and preserving mixed user text/result order.
|
|
105
|
+
- Warn and fall back to an empty canonical tool result when Gemini
|
|
106
|
+
`functionResponse.response` payloads cannot be JSON serialized.
|
|
107
|
+
- Map Gemini policy-blocked finish reasons, including blocklist, prohibited
|
|
108
|
+
content, SPII, Model Armor and image safety stops, to the neutral
|
|
109
|
+
`content_filter` finish reason instead of `unknown`.
|
|
110
|
+
- Preserve empty canonical user turns, with `dropped-content` warnings, when
|
|
111
|
+
Anthropic or Gemini document URLs cannot be represented in OpenAI Chat
|
|
112
|
+
Completions content.
|
|
113
|
+
- Use the tool-call id as the Gemini `functionResponse.name` fallback when a
|
|
114
|
+
standalone canonical tool message has an empty name.
|
|
115
|
+
- Warn on Anthropic `tool_result.tool_use_id` values that are missing or do not
|
|
116
|
+
match a prior `tool_use`, generating deterministic canonical ids for missing
|
|
117
|
+
values while preserving explicit unmapped ids.
|
|
118
|
+
- Regenerate later duplicate Anthropic `tool_result.tool_use_id` values when
|
|
119
|
+
they are explicit but do not match any prior `tool_use`.
|
|
120
|
+
- Emit an empty Anthropic user string, not an empty content-block array, when
|
|
121
|
+
every OpenAI user content part is dropped as unsupported.
|
|
122
|
+
- Reserve Anthropic `tool_result.tool_use_id` values before generating fallback
|
|
123
|
+
`tool_use` ids so explicit result references are not reused by id-less calls.
|
|
124
|
+
|
|
9
125
|
## [0.5.1] - 2026-06-11
|
|
10
126
|
|
|
11
127
|
### Changed
|
|
@@ -108,7 +224,9 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
|
108
224
|
- Audio and document content parts. Audio (OpenAI `input_audio`) converts between
|
|
109
225
|
OpenAI and Gemini; Anthropic has no audio input, so audio is dropped with an
|
|
110
226
|
`unsupported-modality` warning. Documents (OpenAI `file`, Anthropic `document`,
|
|
111
|
-
Gemini `inlineData`
|
|
227
|
+
Gemini `inlineData`) convert across all three when base64-backed; OpenAI
|
|
228
|
+
`file_id` references map to Anthropic file sources and are dropped for Gemini
|
|
229
|
+
with an `unsupported-modality` warning.
|
|
112
230
|
Adds the `MediaPart` type and `unsupported-modality` / `gemini-url-media`
|
|
113
231
|
warning codes. (#5)
|
|
114
232
|
|
package/README.md
CHANGED
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
[](./LICENSE)
|
|
8
8
|
[](./package.json)
|
|
9
9
|
|
|
10
|
-
Convert chat conversations between **OpenAI**, **Anthropic** and **Gemini**
|
|
10
|
+
Convert chat conversations between **OpenAI**, **Anthropic** and **Gemini**
|
|
11
|
+
message formats, and normalize provider responses into the same
|
|
12
|
+
OpenAI-compatible assistant shape. Tool calls, system prompts, roles and
|
|
13
|
+
response metadata handled correctly. Zero dependencies.
|
|
11
14
|
|
|
12
15
|
Switching an agent from one provider to another (or running fallback across providers) means rewriting the whole conversation, and the differences are subtle enough to break at runtime:
|
|
13
16
|
|
|
@@ -15,7 +18,8 @@ Switching an agent from one provider to another (or running fallback across prov
|
|
|
15
18
|
- The assistant role is `assistant` in OpenAI and Anthropic but `model` in Gemini.
|
|
16
19
|
- Tool-call arguments are a **JSON string** in OpenAI but a **parsed object** in Anthropic and Gemini.
|
|
17
20
|
- Tool results are a standalone `role: "tool"` message in OpenAI, a `tool_result` block inside a user turn in Anthropic, and a `functionResponse` part in Gemini.
|
|
18
|
-
- Gemini
|
|
21
|
+
- Gemini can match tool calls to results **by id when present** or by function
|
|
22
|
+
name when ids are omitted, while OpenAI and Anthropic require ids.
|
|
19
23
|
- Anthropic and Gemini reject consecutive same-role turns; OpenAI does not.
|
|
20
24
|
|
|
21
25
|
`llm-messages` handles all of it. Write the conversation once, send it to any provider.
|
|
@@ -28,13 +32,19 @@ npm install llm-messages
|
|
|
28
32
|
|
|
29
33
|
Requires Node 18+. Ships ESM and CommonJS with full TypeScript types.
|
|
30
34
|
|
|
35
|
+
CommonJS consumers can import the same package root:
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
const { toAnthropic, toGemini } = require('llm-messages');
|
|
39
|
+
```
|
|
40
|
+
|
|
31
41
|
## Quick start
|
|
32
42
|
|
|
33
43
|
```ts
|
|
34
|
-
import { toAnthropic, toGemini } from 'llm-messages';
|
|
44
|
+
import { toAnthropic, toGemini, type OpenAIMessage } from 'llm-messages';
|
|
35
45
|
|
|
36
46
|
// A normal OpenAI Chat Completions conversation
|
|
37
|
-
const messages = [
|
|
47
|
+
const messages: OpenAIMessage[] = [
|
|
38
48
|
{ role: 'system', content: 'You are a weather assistant.' },
|
|
39
49
|
{ role: 'user', content: "What's the weather in Paris?" },
|
|
40
50
|
];
|
|
@@ -47,7 +57,9 @@ const gemini = toGemini(messages);
|
|
|
47
57
|
// contents: [{ role: 'user', parts: [{ text: "What's the weather in Paris?" }] }] }
|
|
48
58
|
```
|
|
49
59
|
|
|
50
|
-
##
|
|
60
|
+
## API
|
|
61
|
+
|
|
62
|
+
### The canonical hub
|
|
51
63
|
|
|
52
64
|
OpenAI Chat Completions is the canonical format. Every conversion routes through
|
|
53
65
|
it, so you get a function for each direction:
|
|
@@ -67,12 +79,14 @@ convert(anthropicBody, { from: 'anthropic', to: 'gemini' });
|
|
|
67
79
|
`convert` is fully typed: the input and output shapes are inferred from the
|
|
68
80
|
`from` and `to` providers.
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
### Tool calls round trip losslessly
|
|
71
83
|
|
|
72
84
|
The hard part is tool use, and it survives a full round trip unchanged:
|
|
73
85
|
|
|
74
86
|
```ts
|
|
75
|
-
|
|
87
|
+
import { fromGemini, toGemini, type OpenAIMessage } from 'llm-messages';
|
|
88
|
+
|
|
89
|
+
const messages: OpenAIMessage[] = [
|
|
76
90
|
{
|
|
77
91
|
role: 'assistant',
|
|
78
92
|
content: null,
|
|
@@ -87,16 +101,19 @@ fromGemini(toGemini(messages)); // deep-equals the original `messages`
|
|
|
87
101
|
```
|
|
88
102
|
|
|
89
103
|
Arguments are parsed and re-serialized, ids are preserved (and regenerated
|
|
90
|
-
deterministically when a Gemini payload
|
|
91
|
-
are grouped into the single user turn each provider expects. Anthropic
|
|
104
|
+
deterministically when a Gemini payload does not provide a non-empty string id), and
|
|
105
|
+
parallel tool results are grouped into the single user turn each provider expects. Anthropic
|
|
92
106
|
`tool_result.is_error` is preserved as optional canonical tool-message metadata;
|
|
93
107
|
standalone Gemini `functionResponse.name` is also preserved so orphaned tool
|
|
94
|
-
results can be sent back to Gemini without renaming the function to the id.
|
|
108
|
+
results can be sent back to Gemini without renaming the function to the id. When
|
|
109
|
+
Anthropic includes `tool_result.tool_use_id` or Gemini includes
|
|
110
|
+
`functionResponse.id`, it is matched before provider-specific fallback behavior.
|
|
95
111
|
|
|
96
|
-
|
|
112
|
+
### Conversion report
|
|
97
113
|
|
|
98
|
-
|
|
99
|
-
choice and optionally report it, so you can
|
|
114
|
+
When typed provider payloads contain malformed tool-call or media fields,
|
|
115
|
+
conversions make a deterministic choice and optionally report it, so you can
|
|
116
|
+
surface or log what happened:
|
|
100
117
|
|
|
101
118
|
```ts
|
|
102
119
|
toGemini(messages, {
|
|
@@ -109,13 +126,22 @@ Warning codes: `generated-id`, `unmapped-tool-result`, `merged-role`,
|
|
|
109
126
|
`system-midstream`, `gemini-url-image`, `gemini-url-media`,
|
|
110
127
|
`unsupported-modality`.
|
|
111
128
|
|
|
112
|
-
|
|
129
|
+
Consumers that validate fixture metadata or warning filters can import the same
|
|
130
|
+
stable list from the package root as `warningCodes`.
|
|
131
|
+
|
|
132
|
+
### Reading responses
|
|
113
133
|
|
|
114
134
|
The same idea applies to the read side. Normalize a provider's response body into
|
|
115
135
|
a canonical OpenAI assistant message, plus a neutral finish reason and token usage:
|
|
116
136
|
|
|
117
137
|
```ts
|
|
118
|
-
import {
|
|
138
|
+
import {
|
|
139
|
+
responseFromAnthropic,
|
|
140
|
+
responseFromGemini,
|
|
141
|
+
responseFromOpenAI,
|
|
142
|
+
responseFromOpenAIResponses,
|
|
143
|
+
normalizeResponse,
|
|
144
|
+
} from 'llm-messages';
|
|
119
145
|
|
|
120
146
|
const { message, finishReason, usage } = responseFromAnthropic(anthropicResponseBody);
|
|
121
147
|
// message -> { role: 'assistant', content, tool_calls? } (tool input re-serialized to a JSON string)
|
|
@@ -126,6 +152,12 @@ const responses = responseFromOpenAIResponses(openaiResponsesBody);
|
|
|
126
152
|
// OpenAI Responses API `output_text` items become assistant `content`.
|
|
127
153
|
// `function_call` items become Chat Completions-compatible `tool_calls`.
|
|
128
154
|
|
|
155
|
+
const chat = responseFromOpenAI(openaiChatBody);
|
|
156
|
+
// Chat Completions `choices[0].message.tool_calls` stay Chat Completions-compatible.
|
|
157
|
+
|
|
158
|
+
const gemini = responseFromGemini(geminiResponseBody);
|
|
159
|
+
// Gemini `functionCall` parts become assistant `tool_calls`.
|
|
160
|
+
|
|
129
161
|
// Or dispatch by provider:
|
|
130
162
|
normalizeResponse(geminiResponseBody, { from: 'gemini' });
|
|
131
163
|
normalizeResponse(openaiResponsesBody, { from: 'openai-responses' });
|
|
@@ -133,9 +165,10 @@ normalizeResponse(openaiResponsesBody, { from: 'openai-responses' });
|
|
|
133
165
|
|
|
134
166
|
`finishReason` is normalized to `tool_calls` whenever the model called a tool, even
|
|
135
167
|
for Gemini (which reports `STOP`) and Responses API bodies with `function_call`
|
|
136
|
-
items.
|
|
168
|
+
items. OpenAI Chat Completions, OpenAI Responses, Anthropic and Gemini tool
|
|
169
|
+
calls without a non-empty string id get a deterministic one.
|
|
137
170
|
|
|
138
|
-
|
|
171
|
+
### Format cheatsheet
|
|
139
172
|
|
|
140
173
|
| | OpenAI | Anthropic | Gemini |
|
|
141
174
|
| ---------------- | ------------------------ | -------------------------------- | ------------------------------- |
|
|
@@ -144,15 +177,17 @@ items. Gemini tool calls without an id get a deterministic one.
|
|
|
144
177
|
| Tool call | `tool_calls[].function` | `tool_use` block | `functionCall` part |
|
|
145
178
|
| Call arguments | JSON string | object (`input`) | object (`args`) |
|
|
146
179
|
| Tool result | `role: "tool"` message | `tool_result` block in user turn | `functionResponse` part in user |
|
|
147
|
-
| Match key | `tool_call_id` | `tool_use_id` |
|
|
180
|
+
| Match key | `tool_call_id` | `tool_use_id` | `id` when present, else `name` |
|
|
148
181
|
| Role alternation | not required | strict | strict |
|
|
149
182
|
|
|
150
|
-
|
|
183
|
+
### Images, audio and documents
|
|
151
184
|
|
|
152
185
|
Image parts convert across all three providers:
|
|
153
186
|
|
|
154
187
|
```ts
|
|
155
|
-
|
|
188
|
+
import { toAnthropic, toGemini, type OpenAIMessage } from 'llm-messages';
|
|
189
|
+
|
|
190
|
+
const messages: OpenAIMessage[] = [
|
|
156
191
|
{
|
|
157
192
|
role: 'user',
|
|
158
193
|
content: [
|
|
@@ -162,8 +197,11 @@ const messages = [
|
|
|
162
197
|
},
|
|
163
198
|
];
|
|
164
199
|
|
|
165
|
-
toAnthropic(messages);
|
|
166
|
-
|
|
200
|
+
toAnthropic(messages).messages[0]?.content;
|
|
201
|
+
// -> [{ type: 'text', ... }, { type: 'image', source: { type: 'base64', media_type: 'image/png', data: '...' } }]
|
|
202
|
+
|
|
203
|
+
toGemini(messages).contents[0]?.parts;
|
|
204
|
+
// -> [{ text: 'What is in this image?' }, { inlineData: { mimeType: 'image/png', data: '...' } }]
|
|
167
205
|
```
|
|
168
206
|
|
|
169
207
|
Base64 data URLs round trip losslessly. A remote `https` URL maps to an Anthropic
|
|
@@ -171,28 +209,35 @@ Base64 data URLs round trip losslessly. A remote `https` URL maps to an Anthropi
|
|
|
171
209
|
`gemini-url-image` warning, since Gemini may require the Files API for non-Google
|
|
172
210
|
URIs.
|
|
173
211
|
|
|
212
|
+
If you need to handle image payloads directly, `parseDataUrl` and `toDataUrl`
|
|
213
|
+
are exported for the same base64 data URL shape used by the converters.
|
|
214
|
+
|
|
174
215
|
**Audio** (`input_audio`) and **documents** (`file`, e.g. PDF) convert too. Audio
|
|
175
216
|
moves between OpenAI and Gemini; Anthropic has no audio input, so an audio part is
|
|
176
|
-
dropped with an `unsupported-modality` warning.
|
|
177
|
-
(OpenAI `file`, Anthropic `document`, Gemini
|
|
217
|
+
dropped with an `unsupported-modality` warning. Base64 document payloads convert
|
|
218
|
+
across all three providers (OpenAI `file`, Anthropic `document`, Gemini
|
|
219
|
+
`inlineData`). OpenAI `file_id` document references map to Anthropic `file`
|
|
220
|
+
sources; Gemini has no equivalent and drops them with `unsupported-modality`.
|
|
178
221
|
|
|
179
222
|
## Scope
|
|
180
223
|
|
|
181
224
|
Version 0.x covers text, system prompts, tool calls/results, images, audio and
|
|
182
|
-
documents, which is the core of every agent loop. Unsupported parts are
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
225
|
+
documents, which is the core of every agent loop. Unsupported or lossy parts are
|
|
226
|
+
reported through stable warning codes such as `dropped-content`,
|
|
227
|
+
`unsupported-modality` or provider-specific media warnings rather than failing.
|
|
228
|
+
Provider-only fields are preserved only when the canonical OpenAI-compatible
|
|
229
|
+
shape has an explicit optional metadata field for them, such as Anthropic
|
|
230
|
+
`tool_result.is_error` and standalone Gemini `functionResponse.name`. When that
|
|
231
|
+
metadata has no target-provider equivalent, conversion continues and reports
|
|
232
|
+
`dropped-metadata`.
|
|
188
233
|
|
|
189
234
|
## Roadmap
|
|
190
235
|
|
|
191
236
|
See [ROADMAP.md](./ROADMAP.md) for current maintenance priorities, including
|
|
192
|
-
OpenAI Responses API coverage,
|
|
193
|
-
cases. The [conformance fixtures
|
|
194
|
-
how API credits should be used to refresh deterministic public
|
|
195
|
-
putting secrets in CI.
|
|
237
|
+
OpenAI Responses API coverage, offline conformance fixtures and tool-call edge
|
|
238
|
+
cases. The [conformance fixtures guide](./docs/conformance-fixtures.md)
|
|
239
|
+
describes how API credits should be used to refresh deterministic public
|
|
240
|
+
fixtures without putting secrets in CI.
|
|
196
241
|
|
|
197
242
|
For teams evaluating the package, the
|
|
198
243
|
[adoption guide](./docs/adoption-guide.md) covers the OpenAI-compatible boundary,
|
package/ROADMAP.md
CHANGED
|
@@ -15,11 +15,11 @@ fallback behavior matter.
|
|
|
15
15
|
|
|
16
16
|
Public issue: https://github.com/slegarraga/llm-messages/issues/6
|
|
17
17
|
|
|
18
|
-
2. **
|
|
18
|
+
2. **Provider-backed fixture refreshes**
|
|
19
19
|
|
|
20
20
|
Add provider-backed fixture generation for OpenAI, Anthropic and Gemini
|
|
21
|
-
payloads, keeping the committed
|
|
22
|
-
without API keys.
|
|
21
|
+
payloads, while keeping the committed conformance fixtures deterministic,
|
|
22
|
+
offline, and safe to run without API keys.
|
|
23
23
|
|
|
24
24
|
Plan: [docs/conformance-fixtures.md](./docs/conformance-fixtures.md)
|
|
25
25
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported versions
|
|
4
|
+
|
|
5
|
+
The latest published `0.x` release receives security fixes.
|
|
6
|
+
|
|
7
|
+
## Reporting a vulnerability
|
|
8
|
+
|
|
9
|
+
Please report security issues privately rather than opening a public issue.
|
|
10
|
+
|
|
11
|
+
- Use GitHub's [private vulnerability reporting](https://github.com/slegarraga/llm-messages/security/advisories/new), or
|
|
12
|
+
- Email **sebastian@0a.cl** with the details.
|
|
13
|
+
|
|
14
|
+
Include a description, a reproduction, and the impact. You can expect an initial
|
|
15
|
+
response within a few days. Once a fix is released, we are happy to credit you in
|
|
16
|
+
the advisory unless you prefer to remain anonymous.
|
|
17
|
+
|
|
18
|
+
## Scope
|
|
19
|
+
|
|
20
|
+
`llm-messages` has zero runtime dependencies and performs only in-memory data
|
|
21
|
+
transformation: it does not make network requests, read or write files, or
|
|
22
|
+
execute code from its input. The most relevant risks are denial of service from
|
|
23
|
+
pathological input (for example, deeply nested structures). Reports along those
|
|
24
|
+
lines are welcome.
|