@flink-app/openai-adapter 2.0.0-alpha.100

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) Frost Experience AB https://www.frost.se
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,624 @@
1
+ # @flink-app/openai-adapter
2
+
3
+ OpenAI adapter for the Flink AI framework using the **Responses API** - OpenAI's modern API that provides step-aware reasoning, explicit tool invocation, and better performance.
4
+
5
+ ## Why Responses API?
6
+
7
+ This adapter uses OpenAI's **Responses API** instead of the older Chat Completions API, providing:
8
+
9
+ - **🔧 Step-aware reasoning**: Model returns multiple tool calls as explicit, typed items in a single response
10
+ - **⚡ Better performance**: 3% improvement on SWE-bench, 5% on TAUBench vs Chat Completions
11
+ - **📦 First-class tool steps**: Tool calls and results are structured items, not message hacks
12
+ - **🎯 Future-proof**: All new OpenAI features will land in Responses API first
13
+
14
+ ## Important: Understanding the Agent Loop
15
+
16
+ **The Responses API does NOT run your agent loop.**
17
+
18
+ What it provides:
19
+ - Multiple tool calls in **one response** (you still execute them)
20
+ - Structured step types (message, function_call, function_call_output)
21
+
22
+ What **Flink handles** (via AgentRunner):
23
+ - Tool execution
24
+ - Multi-turn loops (API → execute tools → API → execute tools → done)
25
+ - Deciding when to stop
26
+ - Managing conversation state
27
+
28
+ This separation is intentional - it gives you full control over agent behavior while leveraging better API primitives.
29
+
30
+ ## Installation
31
+
32
+ ```bash
33
+ npm install @flink-app/openai-adapter
34
+ # or
35
+ pnpm add @flink-app/openai-adapter
36
+ ```
37
+
38
+ The `openai` package is included as a dependency, so you don't need to install it separately.
39
+
40
+ ## Usage
41
+
42
+ ### Basic Setup
43
+
44
+ ```typescript
45
+ import { OpenAIAdapter } from "@flink-app/openai-adapter";
46
+ import { FlinkApp } from "@flink-app/flink";
47
+
48
+ const app = new FlinkApp({
49
+ ai: {
50
+ llms: {
51
+ default: new OpenAIAdapter({
52
+ apiKey: process.env.OPENAI_API_KEY!,
53
+ model: "gpt-5"
54
+ }),
55
+ },
56
+ },
57
+ });
58
+
59
+ await app.start();
60
+ ```
61
+
62
+ **Legacy API (still supported):**
63
+ ```typescript
64
+ // Backward-compatible constructor
65
+ new OpenAIAdapter(process.env.OPENAI_API_KEY!, "gpt-5")
66
+ ```
67
+
68
+ ### Agent Instructions
69
+
70
+ Define your agent's behavior using the `instructions` property:
71
+
72
+ ```typescript
73
+ // src/agents/support_agent.ts
74
+ export const Agent: FlinkAgentProps = {
75
+ name: "support_agent",
76
+ instructions: "You are a helpful customer support agent.",
77
+ tools: ["get_order_status"],
78
+ model: { adapterId: "default" },
79
+ };
80
+ ```
81
+
82
+ **How it works:**
83
+ - Instructions are prepended as a system message to every conversation
84
+ - Follows Vercel AI SDK pattern for consistency
85
+ - Provides stable agent behavior across all interactions
86
+
87
+ #### Dynamic Context with System Messages
88
+
89
+ For per-request context, add system messages to the conversation:
90
+
91
+ ```typescript
92
+ const result = await ctx.agents.myAgent.execute({
93
+ message: [
94
+ { role: "system", content: "Current user tier: Premium" },
95
+ { role: "user", content: "What can I do?" }
96
+ ]
97
+ });
98
+ ```
99
+
100
+ **Order of messages sent to OpenAI:**
101
+ 1. Agent `instructions` (as system message)
102
+ 2. User-provided system messages (if any)
103
+ 3. Conversation messages
104
+
105
+ This gives you both static agent behavior and dynamic per-request context.
106
+
107
+ ### Structured Outputs
108
+
109
+ Enable structured outputs with JSON schema for 100% reliability in output format:
110
+
111
+ ```typescript
112
+ import { OpenAIAdapter } from "@flink-app/openai-adapter";
113
+
114
+ const adapter = new OpenAIAdapter({
115
+ apiKey: process.env.OPENAI_API_KEY!,
116
+ model: "gpt-5",
117
+ structuredOutput: {
118
+ type: "json_schema",
119
+ name: "car_analysis",
120
+ description: "Analysis of car specifications",
121
+ schema: {
122
+ type: "object",
123
+ properties: {
124
+ brand: { type: "string" },
125
+ model: { type: "string" },
126
+ year: { type: "number" },
127
+ features: {
128
+ type: "array",
129
+ items: { type: "string" }
130
+ }
131
+ },
132
+ required: ["brand", "model", "year"],
133
+ additionalProperties: false
134
+ },
135
+ strict: true // Enforces 100% schema adherence
136
+ }
137
+ });
138
+ ```
139
+
140
+ **Benefits of Structured Outputs:**
141
+ - 100% reliability (vs ~95% with JSON mode)
142
+ - No need for retry logic or manual validation
143
+ - Automatic schema validation during generation
144
+ - Supported on all modern models: `gpt-4.1`, `gpt-5`, `o4-mini`, `o3`
145
+
146
+ ### Conversation Persistence (Recommended)
147
+
148
+ For multi-turn conversations, use `ConversationAgent` to automatically save conversation history:
149
+
150
+ ```typescript
151
+ // src/agents/ChatAgent.ts
152
+ import { ConversationAgent, ConversationData } from "@flink-app/flink";
153
+
154
+ export default class ChatAgent extends ConversationAgent<AppContext> {
155
+ id = "chat-agent";
156
+ description = "Chat assistant with automatic conversation persistence";
157
+ instructions = "You are a helpful assistant...";
158
+ tools = ["search-knowledge"];
159
+
160
+ // Load conversation from your storage backend
161
+ protected async loadConversation(conversationId: string) {
162
+ const conv = await this.ctx.repos.conversationRepo.getById(conversationId);
163
+ return conv ? {
164
+ messages: conv.messages,
165
+ providerMetadata: conv.providerMetadata // ← Preserved for tracking
166
+ } : null;
167
+ }
168
+
169
+ // Save conversation with updated metadata
170
+ protected async saveConversation(conversationId: string, data: ConversationData) {
171
+ await this.ctx.repos.conversationRepo.upsert({
172
+ _id: conversationId,
173
+ messages: data.messages,
174
+ providerMetadata: data.providerMetadata // ← Saved automatically
175
+ });
176
+ }
177
+ }
178
+ ```
179
+
180
+ **What this enables:**
181
+
182
+ 1. **Automatic History Management**: Framework handles full conversation history
183
+ 2. **Metadata Tracking**: Provider metadata preserved for debugging and future use
184
+ 3. **Storage Flexibility**: Works with MongoDB, Redis, in-memory, or any backend
185
+ 4. **Type Safety**: Abstract methods enforce consistent implementation
186
+
187
+ **Example Storage Backends:**
188
+ - [MongoDB](../../packages/demo-app/src/agents/CarPersistentAgent.ts) - Production-ready persistent storage
189
+ - [In-Memory](../../packages/demo-app/src/agents/examples/InMemoryPersistentAgent.ts) - Development/testing
190
+
191
+ **How Provider Metadata Works:**
192
+
193
+ 1. First turn: Agent executes, adapter may return provider-specific metadata
194
+ 2. `saveConversation()` stores messages + metadata
195
+ 3. Second turn: `loadConversation()` returns messages + metadata
196
+ 4. Framework populates `input.providerMetadata` for tracking/debugging
197
+ 5. Full conversation history is always sent for reliability
198
+
199
+ **Note:** Provider metadata is namespaced by adapter (e.g., `{ openai: {...}, anthropic: {...} }`) for multi-provider support.
200
+
201
+ ## Debug Logging
202
+
203
+ The adapter includes component-specific logging to help debug API requests and responses:
204
+
205
+ ```typescript
206
+ const adapter = new OpenAIAdapter({
207
+ apiKey: process.env.OPENAI_API_KEY!,
208
+ model: "gpt-5",
209
+ debug: true // Enable debug logging for this adapter
210
+ });
211
+ ```
212
+
213
+ **What gets logged:**
214
+
215
+ When `debug: true`:
216
+ - ✅ Initialization confirmation
217
+ - ✅ Request metadata (model, message count, tool count, token limits)
218
+ - ✅ Full request parameters sent to OpenAI
219
+ - ✅ Tool call decisions made by the LLM
220
+ - ✅ Token usage and performance metrics
221
+ - ✅ Response IDs for conversation continuation
222
+ - ✅ Error details with context
223
+
224
+ When `debug: false` (default):
225
+ - ✅ Request completion with token usage (info level)
226
+ - ✅ Errors with context
227
+
228
+ **Log Output Example:**
229
+
230
+ ```bash
231
+ 2026-02-15 [OpenAI] [INFO] OpenAI adapter initialized with debug logging enabled
232
+ 2026-02-15 [OpenAI] [DEBUG] Starting OpenAI stream request {"model":"gpt-5","messageCount":2,"toolCount":3}
233
+ 2026-02-15 [OpenAI] [DEBUG] Stream connection established
234
+ 2026-02-15 [OpenAI] [DEBUG] LLM decided to call tool {"name":"get_weather","call_id":"call_abc123"}
235
+ 2026-02-15 [OpenAI] [INFO] OpenAI request completed {"inputTokens":150,"outputTokens":80,"totalTokens":230}
236
+ ```
237
+
238
+ **Environment-Based Configuration:**
239
+
240
+ You can also enable debug logging via environment variables without code changes:
241
+
242
+ ```bash
243
+ # Enable debug for OpenAI adapter specifically
244
+ DEBUG=OpenAI npm start
245
+
246
+ # Enable debug for multiple components
247
+ DEBUG=OpenAI,Database npm start
248
+
249
+ # Set global log level
250
+ LOG_LEVEL=debug npm start
251
+ ```
252
+
253
+ **Programmatic Control:**
254
+
255
+ For dynamic control at runtime:
256
+
257
+ ```typescript
258
+ import { FlinkLogFactory } from "@flink-app/flink";
259
+
260
+ // Enable debug for OpenAI adapter
261
+ FlinkLogFactory.setComponentLevel("OpenAI", "debug");
262
+
263
+ // Later, disable it
264
+ FlinkLogFactory.setComponentLevel("OpenAI", "info");
265
+ ```
266
+
267
+ **Benefits:**
268
+ - 🔍 Debug API requests without flooding other logs
269
+ - 📊 Track token usage per request
270
+ - 🐛 Investigate tool calling issues
271
+ - ⚡ Monitor performance and latency
272
+ - 🎯 Component-specific logging (OpenAI logs don't affect Database, Cache, etc.)
273
+
274
+ See [Flink Logging Guide](../../docs/LOGGING.md) for more details on component-specific logging.
275
+
276
+ ## Cache Metrics & Cost Optimization
277
+
278
+ The OpenAI adapter automatically captures detailed cache metrics to help you optimize costs and understand performance:
279
+
280
+ ```typescript
281
+ const result = await ctx.agents.myAgent.execute({
282
+ message: "What's the weather?"
283
+ });
284
+
285
+ console.log(result.usage);
286
+ // {
287
+ // inputTokens: 2006,
288
+ // outputTokens: 300,
289
+ // cachedInputTokens: 1920 // 95% cache hit!
290
+ // }
291
+
292
+ // Calculate actual billed input tokens
293
+ const billedInputTokens = result.usage.inputTokens - (result.usage.cachedInputTokens || 0);
294
+ console.log(`Only ${billedInputTokens} tokens charged at full rate`);
295
+ // "Only 86 tokens charged at full rate"
296
+
297
+ // Estimate cost savings (cached tokens are ~10% of regular cost)
298
+ const regularCost = billedInputTokens * 1.0;
299
+ const cachedCost = (result.usage.cachedInputTokens || 0) * 0.1;
300
+ const totalCost = regularCost + cachedCost;
301
+ console.log(`Estimated cost factor: ${totalCost} (vs ${result.usage.inputTokens} without caching)`);
302
+ // "Estimated cost factor: 278 (vs 2006 without caching)" - 86% savings!
303
+ ```
304
+
305
+ **Cache Metrics:**
306
+ - `inputTokens`: Total input tokens (including cached)
307
+ - `outputTokens`: Total output tokens
308
+ - `cachedInputTokens`: Input tokens served from cache (10% cost)
309
+
310
+ **OpenAI Caching:**
311
+ - Cached tokens cost ~10% of regular tokens
312
+ - Automatic caching for repeated context
313
+ - No configuration needed - OpenAI handles it automatically
314
+
315
+ **When Caching Helps Most:**
316
+ - Long system prompts used across requests
317
+ - Repeated context in multi-turn conversations
318
+ - Few-shot examples in prompts
319
+ - Large knowledge bases in context
320
+
321
+ **Logging:**
322
+ When debug mode is enabled, cache metrics are automatically logged:
323
+
324
+ ```bash
325
+ 2026-02-23 [flink.ai.openai] [INFO] OpenAI request completed {
326
+ "inputTokens": 2006,
327
+ "outputTokens": 300,
328
+ "cachedInputTokens": 1920,
329
+ "totalTokens": 2306,
330
+ "status": "completed",
331
+ "model": "gpt-5"
332
+ }
333
+ ```
334
+
335
+ ## Multiple Adapters
336
+
337
+ You can register multiple OpenAI adapters with different configurations:
338
+
339
+ ```typescript
340
+ import { OpenAIAdapter } from "@flink-app/openai-adapter";
341
+ import { FlinkApp } from "@flink-app/flink";
342
+
343
+ const app = new FlinkApp({
344
+ ai: {
345
+ llms: {
346
+ // Default GPT-5 - best for general tasks
347
+ default: new OpenAIAdapter({
348
+ apiKey: process.env.OPENAI_API_KEY!,
349
+ model: "gpt-5"
350
+ }),
351
+
352
+ // Fast reasoning model - cost-efficient
353
+ fast: new OpenAIAdapter({
354
+ apiKey: process.env.OPENAI_API_KEY!,
355
+ model: "o4-mini"
356
+ }),
357
+
358
+ // Maximum intelligence for complex reasoning
359
+ smart: new OpenAIAdapter({
360
+ apiKey: process.env.OPENAI_API_KEY!,
361
+ model: "o3"
362
+ }),
363
+
364
+ // With structured output
365
+ structured: new OpenAIAdapter({
366
+ apiKey: process.env.OPENAI_API_KEY!,
367
+ model: "gpt-5",
368
+ structuredOutput: {
369
+ type: "json_schema",
370
+ name: "response",
371
+ schema: { /* your schema */ },
372
+ strict: true
373
+ }
374
+ }),
375
+ },
376
+ },
377
+ });
378
+ ```
379
+
380
+ ## Using in Agents
381
+
382
+ Reference the adapter by its registered ID in your agent configuration:
383
+
384
+ ```typescript
385
+ // src/agents/support_agent.ts
386
+ import { FlinkAgentProps } from "@flink-app/flink";
387
+
388
+ export const Agent: FlinkAgentProps = {
389
+ name: "support_agent",
390
+ description: "Customer support assistant",
391
+ instructions: "You are a helpful customer support agent.",
392
+ tools: ["get_order_status", "search_knowledge_base"],
393
+ model: {
394
+ adapterId: "default", // Uses the "default" adapter
395
+ maxTokens: 2000,
396
+ temperature: 0.7,
397
+ },
398
+ };
399
+ ```
400
+
401
+ ## Supported Models
402
+
403
+ This adapter works with all OpenAI models available via the Responses API. The latest models (as of 2026) offer significant improvements:
404
+
405
+ ### GPT-5 Series (Recommended)
406
+
407
+ - **GPT-5**: `gpt-5`
408
+ - Latest and most capable model
409
+ - Best for general-purpose applications
410
+ - Excellent at coding, reasoning, and agentic tasks
411
+
412
+ ### GPT-4.1 Series
413
+
414
+ - **GPT-4.1**: `gpt-4.1`
415
+ - Smartest non-reasoning model
416
+ - Excellent at coding tasks
417
+ - Strong at precise instruction following
418
+ - Best for web development and technical tasks
419
+
420
+ - **GPT-4.1 mini**: `gpt-4.1-mini`
421
+ - Smaller, faster, more cost-efficient
422
+ - Good balance of capability and cost
423
+
424
+ - **GPT-4.1 nano**: `gpt-4.1-nano`
425
+ - Ultra-fast and cost-efficient
426
+ - Best for simple, high-volume tasks
427
+
428
+ ### O-Series Reasoning Models
429
+
430
+ - **o4-mini**: `o4-mini` (recommended for reasoning tasks)
431
+ - Fast, cost-efficient reasoning model
432
+ - Best-performing on AIME 2024 and 2025 benchmarks
433
+ - Optimized for mathematical and logical reasoning
434
+
435
+ - **o3**: `o3`
436
+ - Advanced reasoning model for complex tasks
437
+ - State-of-the-art performance on coding, math, and science
438
+ - Excellent at Codeforces, SWE-bench, and MMMU
439
+
440
+ - **o3-pro**: `o3-pro`
441
+ - Premium reasoning model (Pro users only)
442
+ - Designed to think longer and provide most reliable responses
443
+
444
+ ### Legacy Models
445
+
446
+ For backwards compatibility:
447
+
448
+ - **GPT-4 Turbo**: `gpt-4-turbo`
449
+ - **GPT-4**: `gpt-4`
450
+ - **GPT-3.5 Turbo**: `gpt-3.5-turbo`
451
+
452
+ **Note**: Some older models (GPT-4o, early GPT-4.1 variants) are being retired in 2026. Migrate to the latest models for continued support.
453
+
454
+ ## Model Selection Guide
455
+
456
+ | Use Case | Recommended Model | Why |
457
+ |----------|------------------|-----|
458
+ | General development | `gpt-5` | Latest and most capable |
459
+ | Coding & technical | `gpt-4.1` | Best instruction following |
460
+ | High-volume tasks | `gpt-4.1-mini` | Cost-efficient with good performance |
461
+ | Mathematical reasoning | `o4-mini` | Optimized for math, fast and cost-efficient |
462
+ | Complex problem-solving | `o3` | State-of-the-art reasoning |
463
+ | Mission-critical | `o3-pro` | Maximum reliability (Pro users) |
464
+
465
+ ## Features
466
+
467
+ - ✅ **Step-based tool calling** - Multiple tool calls in one response as typed items
468
+ - ✅ **Event-based streaming** - Proper event taxonomy (not just token streaming)
469
+ - ✅ **Structured outputs** with JSON schema (100% reliability)
470
+ - ✅ **First-class tool steps** - function_call and function_call_output as explicit types
471
+ - ✅ Support for all OpenAI models
472
+ - ✅ 3-5% performance improvement over Chat Completions
473
+
474
+ ### What Makes Responses API Different
475
+
476
+ The key difference is **how tool calls are represented**, not who executes them:
477
+
478
+ **Chat Completions (old):**
479
+ ```
480
+ Response: {
481
+ message: {
482
+ content: "...",
483
+ tool_calls: [...] // Tool calls embedded in message
484
+ }
485
+ }
486
+
487
+ You: Extract tool calls, execute them, create new messages, call API again
488
+ ```
489
+
490
+ **Responses API (new):**
491
+ ```
492
+ Response: {
493
+ output: [
494
+ { type: "message", content: "..." },
495
+ { type: "function_call", name: "...", call_id: "..." },
496
+ { type: "function_call", name: "...", call_id: "..." } // Multiple calls!
497
+ ]
498
+ }
499
+
500
+ You: Extract tool calls, execute them, create function_call_output items, call API again
501
+ ```
502
+
503
+ **Key improvements:**
504
+ - **Multiple tool calls per response**: Model can request several tools at once
505
+ - **Explicit step types**: No more message role gymnastics
506
+ - **Better structured**: function_call_output vs cramming into user messages
507
+ - **Clearer semantics**: Steps are first-class, not message metadata
508
+
509
+ **Still your responsibility:**
510
+ - Executing the tools
511
+ - Deciding when to stop the loop
512
+ - Managing conversation history
513
+
514
+ ## API
515
+
516
+ ### `OpenAIAdapter`
517
+
518
+ ```typescript
519
+ interface OpenAIAdapterOptions {
520
+ apiKey: string;
521
+ model: string;
522
+ structuredOutput?: {
523
+ type: "json_schema";
524
+ name: string;
525
+ description?: string;
526
+ schema: Record<string, any>;
527
+ strict?: boolean;
528
+ };
529
+ }
530
+
531
+ class OpenAIAdapter implements LLMAdapter {
532
+ constructor(options: OpenAIAdapterOptions);
533
+ constructor(apiKey: string, model: string); // Legacy
534
+ }
535
+ ```
536
+
537
+ #### Parameters
538
+
539
+ - `apiKey`: Your OpenAI API key
540
+ - `model`: The OpenAI model to use (e.g., "gpt-5", "o4-mini")
541
+ - `structuredOutput`: Optional JSON schema for structured outputs
542
+
543
+ ## Architecture Notes
544
+
545
+ ### Responses API vs Chat Completions
546
+
547
+ This adapter uses OpenAI's **Responses API**, which differs from Chat Completions in several ways:
548
+
549
+ **Request Format:**
550
+ - Chat Completions: `messages` array with system/user/assistant roles
551
+ - Responses API: `input` array with typed items (messages, function_call_outputs, etc.) + separate `instructions` field
552
+
553
+ **Response Format:**
554
+ - Chat Completions: `choices[0].message.content`
555
+ - Responses API: `output` array of items with type `message`, `function_call`, etc.
556
+
557
+ **Tool/Function Format:**
558
+ - Chat Completions: Externally-tagged `{ type: "function", function: {...} }`
559
+ - Responses API: Internally-tagged `{ type: "function", name: "...", ... }` (strict by default)
560
+
561
+ **Structured Outputs:**
562
+ - Chat Completions: `response_format: { type: "json_schema", json_schema: {...} }`
563
+ - Responses API: `text: { format: { type: "json_schema", ... } }`
564
+
565
+ ### Flink Integration
566
+
567
+ The adapter seamlessly integrates with Flink's `LLMAdapter` interface:
568
+
569
+ - Flink's `instructions` → Responses API `instructions`
570
+ - Flink's `messages` → Converted to Responses API `input` items (typed steps)
571
+ - Flink's tool schema → Converted to Responses API function format (internally-tagged, strict by default)
572
+ - Responses `output` → Extracted to Flink's `LLMResponse` format
573
+
574
+ **Each API call is one turn:**
575
+ - Flink calls `adapter.execute()` → One Responses API request
576
+ - Response may contain multiple tool calls (as separate items)
577
+ - Flink's AgentRunner executes those tools
578
+ - Flink calls `adapter.execute()` again with tool results → Another Responses API request
579
+ - Repeat until no more tool calls
580
+
581
+ This is the standard agent loop architecture used by modern frameworks (LangGraph, Vercel AI SDK, etc.)
582
+
583
+ ## Migration from Chat Completions
584
+
585
+ If you're coming from the Chat Completions API, the good news is: **no code changes needed!**
586
+
587
+ The adapter handles all the differences internally:
588
+
589
+ ```typescript
590
+ // This works the same way with both APIs
591
+ const app = new FlinkApp({
592
+ ai: {
593
+ llms: {
594
+ default: new OpenAIAdapter({
595
+ apiKey: process.env.OPENAI_API_KEY!,
596
+ model: "gpt-5" // Just update the model
597
+ }),
598
+ },
599
+ },
600
+ });
601
+ ```
602
+
603
+ Benefits of upgrading:
604
+ - ✅ Step-aware reasoning (multiple tool calls per response)
605
+ - ✅ Better performance (3-5% improvement on benchmarks)
606
+ - ✅ First-class tool steps (cleaner than message role hacks)
607
+ - ✅ Future-proof (new features land here first)
608
+
609
+ ## Requirements
610
+
611
+ - Node.js >= 18
612
+ - @flink-app/flink >= 1.0.0
613
+ - openai >= 4.77.0 (with Responses API support)
614
+
615
+ ## License
616
+
617
+ MIT
618
+
619
+ ## Resources
620
+
621
+ - [OpenAI Responses API Documentation](https://platform.openai.com/docs/api-reference/responses)
622
+ - [Migrate to the Responses API Guide](https://platform.openai.com/docs/guides/migrate-to-responses)
623
+ - [Why we built the Responses API](https://developers.openai.com/blog/responses-api/)
624
+ - [Structured Outputs Guide](https://platform.openai.com/docs/guides/structured-outputs)