legion-llm 0.5.8 → 0.5.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2ce29d10392a53a933f031e6a19d4437ea57ee6f78710946624275c5c4ac083d
4
- data.tar.gz: b372503d1dd95713e3a8b1471715fb10d05aae541e8a9631e6f35fc59b812bb5
3
+ metadata.gz: 32956f9193bba2e3267fe4eb0ac772c9737c572d2071a1f2748fc467efe480eb
4
+ data.tar.gz: 8cdac1300c401badf1058a8a6d6a973b3f4d542aca96d9cfc9c6e5c1a8c4af21
5
5
  SHA512:
6
- metadata.gz: 66c5ee8b6f787d69706e32691603b83c895144bc439732810789761680fcb197511a0c0ce31aa210286ef82e279e4d08d44c21b1a7a5cac9c0bd95dfe8573fbf
7
- data.tar.gz: ca65b36532cb559c9d0b53ffacc2dfdb404a19e7470f53e933aee6dd686fd97e87e904bd89f10b3fdd593fc78622646c5a0cabe87a1631416af207c2e88dcb50
6
+ metadata.gz: 3d1e57da89f74ce3208cf0052f48a7a6bb0293bbbec0cb47a24f63ebc9d135e961343d9d76deac48f994465114c3ab6f1c0d0a355800d039e5080090aacd3a1a
7
+ data.tar.gz: 53b76addea4596c1cfbff168e430abdf652db9b6d1b3fcb75ac1a732990d9cde7eea9f53d4255162366eabc97f881380b88d95f20e06ce4e946bfa4dec392af8
@@ -0,0 +1,7 @@
1
+ # Auto-generated from team-config.yml
2
+ # Team: ai
3
+ #
4
+ # To apply: scripts/apply-codeowners.sh legion-llm
5
+
6
+ * @LegionIO/maintainers
7
+ * @LegionIO/ai
@@ -0,0 +1,18 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: bundler
4
+ directory: /
5
+ schedule:
6
+ interval: weekly
7
+ day: monday
8
+ open-pull-requests-limit: 5
9
+ labels:
10
+ - "type:dependencies"
11
+ - package-ecosystem: github-actions
12
+ directory: /
13
+ schedule:
14
+ interval: weekly
15
+ day: monday
16
+ open-pull-requests-limit: 5
17
+ labels:
18
+ - "type:dependencies"
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Legion LLM Changelog
2
2
 
3
+ ## [0.5.9] - 2026-03-25
4
+
5
+ ### Added
6
+ - Provider-aware embedding model resolution: `Embeddings.generate` and `generate_batch` accept `provider:` parameter
7
+ - `PROVIDER_EMBEDDING_MODELS` constant maps providers to their default embedding models (bedrock: `amazon.titan-embed-text-v2`, openai: `text-embedding-3-small`, gemini: `text-embedding-004`, ollama: `mxbai-embed-large`)
8
+ - Embedding fallback chain: explicit `provider:`/`model:` -> `llm.embeddings.provider`/`default_model` settings -> derive from `llm.default_provider` -> `text-embedding-3-small`
9
+ - Embedding results now include `:provider` key in response hash
10
+
3
11
  ## [0.5.8] - 2026-03-25
4
12
 
5
13
  ### Added
@@ -0,0 +1,203 @@
1
+ # LLM Pipeline Gap Analysis
2
+
3
+ **Date**: 2026-03-23
4
+ **Scope**: All 5 implementation plans vs routing-reenvisioned.md, llm-schema-spec.md, TODO.md, design-backlog.md, GAS docs, mind_growth_TODO, async-updates-TODO, teams-rag-bridge idea
5
+ **Author**: Gap analysis session
6
+
7
+ ---
8
+
9
+ ## Critical Gaps (Blocks the Vision)
10
+
11
+ ### 1. ConversationStore -- No Plan Builds It
12
+
13
+ The routing-reenvisioned doc's core concept is `ConversationStore` -- per-message persistence, UUID-keyed, the "spine" of the whole system. Steps 5 (Context Load) and 15 (Context Store) depend on it.
14
+
15
+ **None of the five plans build it.** Plan 1 builds Request/Response structs and the pipeline skeleton. Plan 2 builds GAIA advisory. Plan 3 builds RAG via Apollo. Plan 4 builds MCP client. Plan 5 builds Catalog.
16
+
17
+ The conversation UUID is generated (Plan 1, Task 1 creates the Request struct with `conversation_id`), but there's no `ConversationStore` class, no message table, no persistence. The pipeline creates conversation IDs that go nowhere.
18
+
19
+ **Impact**: The whole portable-conversation vision (start in interlink, continue in CLI, switch providers mid-conversation) has no implementation path. Escalation history, context handoff, and the two-tier cache (local vs shared) are all unbuilt. The spool-on-failure pattern for Step 12 (routing-reenvisioned resolved design decision) has no plan.
20
+
21
+ **Recommendation**: Add a Plan 1.5 or extend Plan 1 with ConversationStore tasks. Dependencies: legion-data (SQLite/PG via Sequel). Schema: `conversations` table (id, created_at, metadata) + `conversation_messages` table (conversation_id, seq, role, content, provider, tokens, timestamp). Hot layer: in-memory LRU. Cold reads: DB on cache miss. Writes: append to in-memory + INSERT (delta, never full rewrite). Spool on DB failure via `Legion::Data::Spool`.
22
+
23
+ ### 2. Streaming -- Pipeline Has No Streaming Path
24
+
25
+ routing-reenvisioned.md lists streaming as Open Decision #2. The schema spec defines streaming chunks. The provider adapter contract specifies `chat_stream`. But:
26
+
27
+ - Plan 1's pipeline skeleton has no streaming path
28
+ - The Executor calls `session.ask()` (blocking), not `session.stream()`
29
+ - No plan addresses how streaming interacts with context store, audit, or RAG enrichment injection
30
+ - The existing `chat_stream` on ProviderAdapter is defined but the pipeline has no way to invoke it
31
+
32
+ **Impact**: The CLI chat already streams via RubyLLM. Wiring it into the new pipeline will either break streaming or force the CLI to bypass the pipeline entirely, defeating the "one entry point" principle.
33
+
34
+ **Recommendation**: Plan 1 needs a streaming variant of the Executor. Options: (a) `Executor#call_stream` that yields chunks and runs post-response steps on completion, or (b) a StreamingExecutor subclass. Context store and audit should fire on stream completion, not per-chunk. RAG enrichment injection happens before the provider call (Step 8), so it works regardless of streaming.
35
+
36
+ ---
37
+
38
+ ## Important Gaps (Doesn't Block But Creates Drift)
39
+
40
+ ### 3. Step Numbering Mismatch Between Documents
41
+
42
+ The routing-reenvisioned doc defines a **16-step pipeline**. The unified integration design doc defines an **18-step pipeline**. The plan files follow the 18-step version. Step numbers shifted:
43
+
44
+ | routing-reenvisioned.md | unified-integration-design.md | Change |
45
+ |---|---|---|
46
+ | Step 0: Tracing | Step 0: Tracing | same |
47
+ | Step 1: UUID | Step 1: Idempotency (NEW) | added |
48
+ | -- | Step 2: UUID | renumbered |
49
+ | Step 2: Caller Auth | Step 3: Context Load | merged/split differently |
50
+ | Step 3: RBAC + Classification | Step 4: RBAC, Step 5: Classification | split into two |
51
+ | -- | Step 6: Billing (NEW) | added |
52
+
53
+ **Impact**: Future sessions referencing "Step 7" will get different answers depending on which doc they read.
54
+
55
+ **Recommendation**: Add a "Superseded by" note at the top of routing-reenvisioned.md pointing to the unified integration design doc. The reenvisioned doc remains valuable as the conceptual foundation but the design doc is the authoritative step reference.
56
+
57
+ ### 4. Gateway Absorption Teardown Not Explicitly Planned
58
+
59
+ routing-reenvisioned.md says `lex-llm-gateway` gets **absorbed** into `legion-llm`. Plan 1 mentions gateway absorption in its scope header and has tasks for metering integration (Task 10) and fleet dispatch (Task 11). But there's no explicit task to:
60
+
61
+ - Deprecate/remove `lex-llm-gateway`
62
+ - Update LegionIO's boot sequence to stop loading it
63
+ - Remove the `_direct` variant indirection (`chat()` -> gateway -> `chat_direct()`)
64
+ - Update `lib/legion/llm.rb` to remove the `begin/rescue LoadError` gateway detection
65
+
66
+ **Impact**: Two code paths coexist. The gateway delegation pattern (`chat` vs `chat_direct`) becomes confusing when the pipeline already handles metering and fleet dispatch.
67
+
68
+ **Recommendation**: Add a cleanup task at the end of Plan 1 (or as Plan 1 Task 16) that removes gateway delegation from `legion-llm` and marks `lex-llm-gateway` as deprecated. Don't delete the gateway gem yet -- just stop loading it.
69
+
70
+ ### 5. Provider Adapter Contract Not Implemented
71
+
72
+ routing-reenvisioned.md defines `ProviderAdapter` with `chat`, `chat_stream`, `capabilities`, `health_check`, `token_estimate`. The current extensions-ai gems (lex-claude, lex-bedrock, etc.) don't implement this interface -- they use RubyLLM under the hood with their own patterns.
73
+
74
+ Plan 1 Tasks 8-9 (Provider Call steps) delegate to RubyLLM, not to a formal ProviderAdapter. The `ProviderRegistry` described in the reenvisioned doc (`Legion::LLM::ProviderRegistry.get(:claude)`) doesn't exist in any plan.
75
+
76
+ **Impact**: The pipeline calls RubyLLM directly (works fine), but the clean provider abstraction is aspirational. If you ever want to swap RubyLLM for direct HTTP calls or add a non-RubyLLM provider, this gap matters.
77
+
78
+ **Recommendation**: Accept this as intentional tech debt for now. The ProviderAdapter contract is the right long-term design but RubyLLM works. Flag for a future plan when provider diversity demands it.
79
+
80
+ ### 6. Error Hierarchy Not Created
81
+
82
+ routing-reenvisioned.md defines:
83
+ ```
84
+ Legion::LLM::AuthError -> don't retry, fix credentials
85
+ Legion::LLM::RateLimitError -> retry with backoff
86
+ Legion::LLM::ContextOverflow -> reduce context, retry
87
+ Legion::LLM::ProviderError -> transient, retry
88
+ Legion::LLM::ProviderDown -> circuit breaker, failover
89
+ Legion::LLM::UnsupportedCapability -> route elsewhere
90
+ ```
91
+
92
+ Currently only `EscalationExhausted`, `DaemonDeniedError`, `DaemonRateLimitedError` exist. No plan creates the full hierarchy. The pipeline's error handling uses generic `rescue StandardError`.
93
+
94
+ **Impact**: Circuit breaker logic, retry decisions, and failover all depend on error classification. Without typed errors, the pipeline can't distinguish "retry with backoff" from "don't retry, fix credentials."
95
+
96
+ **Recommendation**: Add error classes as a small task in Plan 1 Phase A (alongside structs). They're just class definitions -- minimal effort, high value for the provider call step.
97
+
98
+ ### 7. Boot Order GAIA Dependency
99
+
100
+ Current boot order from MEMORY.md:
101
+ ```
102
+ Logging -> Settings -> Crypt -> Transport -> Cache -> Data -> RBAC -> LLM -> GAIA -> ...
103
+ ```
104
+
105
+ The pipeline adds: LLM now needs GAIA (Step 7). GAIA boots **after** LLM.
106
+
107
+ The design handles this gracefully ("if GAIA unavailable, skip silently"), but GAIA advisory is **never** available for the first N requests until GAIA finishes booting and runs its first tick.
108
+
109
+ **Impact**: Acceptable for now. First few requests after boot get no GAIA shaping. Worth documenting.
110
+
111
+ **Recommendation**: No code change needed. Add a note in Plan 2's design that GAIA advisory degrades gracefully during boot and becomes available after GAIA's first tick completes.
112
+
113
+ ---
114
+
115
+ ## Things That Naturally Follow But Aren't Planned
116
+
117
+ ### 8. Teams Bot Migration to Legion::LLM.chat()
118
+
119
+ The `2026-03-22-teams-rag-bridge.md` idea describes the gap: "Nothing reads traces back to inform LLM responses." Plan 3's RAG read path (Step 8) is exactly the mechanism that would solve this -- if the Teams bot routes through `Legion::LLM.chat()` instead of calling `llm_session.ask()` directly.
120
+
121
+ **Recommendation**: After Plan 1 is complete, the Teams bot's `handle_message` should switch from direct `llm_session.ask()` to `Legion::LLM.chat()` with proper caller identity. This isn't in any plan but is the natural follow-up. Add to ideas/.
122
+
123
+ ### 9. TBI Phase 5 is Plan 5's Capability Catalog
124
+
125
+ The design backlog notes TBI Phase 5 (self-generate) and Phase 6 (share protocol) as next items. Plan 5's Capability Catalog is a prerequisite for TBI Phase 5 (self-generated tools need to register in the Catalog). The override confidence mechanism in Plan 5 is essentially TBI learning applied to tool dispatch.
126
+
127
+ **Recommendation**: Update the TBI status in design-backlog.md to note that Plan 5 covers the foundation for Phase 5. The self-generation loop (lex-codegen + lex-eval generating new tools from observed gaps) remains unplanned but the Catalog gives it a registration target.
128
+
129
+ ### 10. lex-knowledge Escalation Gate -- Superseded
130
+
131
+ The async-updates-TODO has a full escalation gate design (Phase 3) with small-model/large-model tiering. The new pipeline's routing (explicit -> rules -> smart -> default) with escalation chains completely supersedes this design.
132
+
133
+ **Recommendation**: Update the async-updates-TODO Phase 3 status to "SUPERSEDED by LLM pipeline routing + escalation chains."
134
+
135
+ ### 11. Caller Authentication Boundary
136
+
137
+ The routing-reenvisioned doc's Step 2 says "validate credential (JWT, API key, session, mTLS, internal)." The pipeline (Plan 1) trusts the caller identity it receives -- actual credential validation happens upstream at the entry point (daemon API controller, MCP server).
138
+
139
+ This is probably the right architecture (pipelines shouldn't validate JWTs), but it's a divergence from the reenvisioned doc's description.
140
+
141
+ **Recommendation**: No code change. Clarify in the design doc that auth happens at entry points, not in the pipeline. The pipeline's RBAC step (Step 4) does authorization ("is this identity permitted?"), not authentication ("is this identity who they claim to be?").
142
+
143
+ ---
144
+
145
+ ## Low Priority / Future
146
+
147
+ ### 12. Fork -- Designed But Unplanned
148
+
149
+ routing-reenvisioned.md describes fork patterns (comparison, consensus, race) at Steps 7-11. The schema spec has `fork` fields. No plan includes fork implementation. The pipeline Executor has no fork path.
150
+
151
+ **Impact**: None now. Fork is a power-user feature for model comparison and A/B testing.
152
+
153
+ **Recommendation**: Track as a future plan. The pipeline architecture supports it (steps 7-11 can execute in parallel per the design) but the Executor needs a fork variant.
154
+
155
+ ### 13. Billing Enforcement
156
+
157
+ The schema spec has extensive billing fields (`budget_id`, `spending_cap`, `cost`). The design doc has Step 6 (Billing). Plan 1 creates a stub RBAC step but no billing step. The HealthTracker has `budget.daily_limit_usd` and `budget.monthly_limit_usd` listed as "future."
158
+
159
+ **Impact**: No budget enforcement. Enterprise customers with per-team spending caps have no gate.
160
+
161
+ **Recommendation**: Track as a separate plan after the core pipeline ships. Billing needs metering data flowing first (Plan 1 Task 10), so it naturally follows.
162
+
163
+ ### 14. Wire Capture
164
+
165
+ The schema spec defines `wire` capture (raw request/response payloads for translator debugging). Plan 1's Response struct includes `wire` as a field, but no plan implements the opt-in capture mechanism.
166
+
167
+ **Impact**: Debugging provider translation issues requires manual logging. Low urgency.
168
+
169
+ **Recommendation**: Implement as needed when debugging a specific provider adapter issue.
170
+
171
+ ### 15. mind_growth Phase 4 (Wiring Loop) Still Blocked
172
+
173
+ Phase 4.1 (Auto-Wiring) needs `lex-cortex / legion-gaia integration` which is marked NOT STARTED. Plan 2 (GAIA Integration) adds advisory hooks but doesn't address cortex wiring. This remains blocked on cortex work outside the LLM pipeline scope.
174
+
175
+ ### 16. GAS Plan 3 Dependency on Plan 2
176
+
177
+ Plan 3 (RAG/GAS) has a "soft dependency" on Plan 2 for `llm.audit` exchange and `GaiaCaller`. Without Plan 2:
178
+ - GAS subscriber (Task 9) has nothing to listen to
179
+ - GAS Phases 3 (Relate) and 4 (Synthesize) fall back to "return empty array"
180
+ - Only the RAG read path (Phase A) delivers real value
181
+
182
+ **Recommendation**: Complete Plan 2 before Plan 3 Phase B (GAS Foundation). Plan 3 Phase A (RAG read path) can proceed independently.
183
+
184
+ ---
185
+
186
+ ## Action Items
187
+
188
+ | Priority | Item | Where |
189
+ |---|---|---|
190
+ | P0 | Design ConversationStore (Plan 1.5 or extend Plan 1) | New plan needed |
191
+ | P0 | Add streaming path to pipeline Executor | Plan 1 amendment |
192
+ | P1 | Add error hierarchy classes | Plan 1 Phase A addition |
193
+ | P1 | Add gateway teardown task | Plan 1 tail-end task |
194
+ | P1 | Mark routing-reenvisioned.md as superseded | routing-reenvisioned.md header |
195
+ | P2 | Clarify auth boundary (entry point vs pipeline) | Design doc note |
196
+ | P2 | Update TBI Phase 5 status re: Plan 5 | design-backlog.md |
197
+ | P2 | Mark lex-knowledge escalation as superseded | async-updates-TODO.md |
198
+ | P2 | Add Teams bot migration to ideas/ | ideas/ |
199
+ | P3 | Track fork, billing, wire capture as future | This doc |
200
+
201
+ ---
202
+
203
+ **This analysis covers all five plans against the full backlog. The two critical gaps (ConversationStore and streaming) should be addressed before Plan 1 is considered complete. Everything else is manageable debt or natural follow-up work.**
@@ -0,0 +1,16 @@
1
+ {
2
+ "llm": {
3
+ "rbac": {
4
+ },
5
+ "providers": {
6
+ },
7
+ "context": {
8
+ },
9
+ "provider_selection": {
10
+ },
11
+ "rag-context_build": {
12
+ },
13
+ "request_normalization": {
14
+ }
15
+ }
16
+ }
@@ -0,0 +1,108 @@
1
+ {
2
+ "model": "claude-opus-4-6-20250415",
3
+ "system": [
4
+ {
5
+ "type": "text",
6
+ "text": "You are a helpful coding assistant."
7
+ },
8
+ {
9
+ "type": "text",
10
+ "text": "Always respond in markdown format.",
11
+ "cache_control": {
12
+ "type": "ephemeral"
13
+ }
14
+ }
15
+ ],
16
+ "messages": [
17
+ {
18
+ "role": "user",
19
+ "content": "What files are in the current directory?"
20
+ },
21
+ {
22
+ "role": "assistant",
23
+ "content": [
24
+ {
25
+ "type": "tool_use",
26
+ "id": "toolu_abc123",
27
+ "name": "list_files",
28
+ "input": {
29
+ "path": "."
30
+ }
31
+ }
32
+ ]
33
+ },
34
+ {
35
+ "role": "user",
36
+ "content": [
37
+ {
38
+ "type": "tool_result",
39
+ "tool_use_id": "toolu_abc123",
40
+ "content": "[\"README.md\", \"src/\", \"lib/\"]"
41
+ }
42
+ ]
43
+ },
44
+ {
45
+ "role": "assistant",
46
+ "content": "The current directory contains README.md, src/, and lib/."
47
+ },
48
+ {
49
+ "role": "user",
50
+ "content": [
51
+ {
52
+ "type": "text",
53
+ "text": "What does this diagram show?"
54
+ },
55
+ {
56
+ "type": "image",
57
+ "source": {
58
+ "type": "base64",
59
+ "media_type": "image/png",
60
+ "data": "iVBORw0KGgo..."
61
+ }
62
+ }
63
+ ]
64
+ }
65
+ ],
66
+ "tools": [
67
+ {
68
+ "name": "list_files",
69
+ "description": "List files in a directory",
70
+ "input_schema": {
71
+ "type": "object",
72
+ "properties": {
73
+ "path": {
74
+ "type": "string",
75
+ "description": "The directory path to list"
76
+ }
77
+ },
78
+ "required": ["path"]
79
+ }
80
+ },
81
+ {
82
+ "name": "read_file",
83
+ "description": "Read the contents of a file",
84
+ "input_schema": {
85
+ "type": "object",
86
+ "properties": {
87
+ "path": {
88
+ "type": "string",
89
+ "description": "The file path to read"
90
+ }
91
+ },
92
+ "required": ["path"]
93
+ }
94
+ }
95
+ ],
96
+ "tool_choice": {
97
+ "type": "auto"
98
+ },
99
+ "max_tokens": 4096,
100
+ "temperature": 0.7,
101
+ "top_p": 1.0,
102
+ "top_k": 40,
103
+ "stop_sequences": ["\n\n---"],
104
+ "stream": false,
105
+ "metadata": {
106
+ "user_id": "user-abc123"
107
+ }
108
+ }
@@ -0,0 +1,90 @@
1
+ {
2
+ "id": "msg_abc123def456",
3
+ "type": "message",
4
+ "role": "assistant",
5
+ "content": [
6
+ {
7
+ "type": "text",
8
+ "text": "The diagram shows a microservices architecture with three main components..."
9
+ }
10
+ ],
11
+ "model": "claude-opus-4-6-20250415",
12
+ "stop_reason": "end_turn",
13
+ "stop_sequence": null,
14
+ "usage": {
15
+ "input_tokens": 1245,
16
+ "output_tokens": 89,
17
+ "cache_creation_input_tokens": 512,
18
+ "cache_read_input_tokens": 200
19
+ },
20
+
21
+ "__comment_tool_call_response": "When the model invokes a tool, content includes tool_use blocks:",
22
+ "__tool_call_example": {
23
+ "content": [
24
+ {
25
+ "type": "text",
26
+ "text": "Let me read that file for you."
27
+ },
28
+ {
29
+ "type": "tool_use",
30
+ "id": "toolu_xyz789",
31
+ "name": "read_file",
32
+ "input": {
33
+ "path": "README.md"
34
+ }
35
+ }
36
+ ],
37
+ "stop_reason": "tool_use"
38
+ },
39
+
40
+ "__comment_streaming": "Streaming responses arrive as SSE events with typed deltas:",
41
+ "__stream_events": [
42
+ {
43
+ "type": "message_start",
44
+ "message": {
45
+ "id": "msg_abc123",
46
+ "type": "message",
47
+ "role": "assistant",
48
+ "content": [],
49
+ "model": "claude-opus-4-6-20250415",
50
+ "usage": {
51
+ "input_tokens": 1245,
52
+ "output_tokens": 0
53
+ }
54
+ }
55
+ },
56
+ {
57
+ "type": "content_block_start",
58
+ "index": 0,
59
+ "content_block": {
60
+ "type": "text",
61
+ "text": ""
62
+ }
63
+ },
64
+ {
65
+ "type": "content_block_delta",
66
+ "index": 0,
67
+ "delta": {
68
+ "type": "text_delta",
69
+ "text": "The diagram"
70
+ }
71
+ },
72
+ {
73
+ "type": "content_block_stop",
74
+ "index": 0
75
+ },
76
+ {
77
+ "type": "message_delta",
78
+ "delta": {
79
+ "stop_reason": "end_turn",
80
+ "stop_sequence": null
81
+ },
82
+ "usage": {
83
+ "output_tokens": 89
84
+ }
85
+ },
86
+ {
87
+ "type": "message_stop"
88
+ }
89
+ ]
90
+ }
@@ -0,0 +1,103 @@
1
+ {
2
+ "__endpoint": "POST https://{endpoint}.openai.azure.com/openai/deployments/{deployment}/chat/completions?api-version=2024-10-21",
3
+ "__auth": "api-key header (NOT Bearer token)",
4
+ "__comment": "Azure OpenAI uses the OpenAI format with deployment-based routing instead of model in body",
5
+
6
+ "messages": [
7
+ {
8
+ "role": "system",
9
+ "content": "You are a helpful coding assistant."
10
+ },
11
+ {
12
+ "role": "user",
13
+ "content": "What files are in the current directory?"
14
+ },
15
+ {
16
+ "role": "assistant",
17
+ "content": null,
18
+ "tool_calls": [
19
+ {
20
+ "id": "call_abc123",
21
+ "type": "function",
22
+ "function": {
23
+ "name": "list_files",
24
+ "arguments": "{\"path\": \".\"}"
25
+ }
26
+ }
27
+ ]
28
+ },
29
+ {
30
+ "role": "tool",
31
+ "tool_call_id": "call_abc123",
32
+ "content": "[\"README.md\", \"src/\", \"lib/\"]"
33
+ },
34
+ {
35
+ "role": "assistant",
36
+ "content": "The current directory contains README.md, src/, and lib/."
37
+ },
38
+ {
39
+ "role": "user",
40
+ "content": [
41
+ {
42
+ "type": "text",
43
+ "text": "What does this diagram show?"
44
+ },
45
+ {
46
+ "type": "image_url",
47
+ "image_url": {
48
+ "url": "data:image/png;base64,iVBORw0KGgo...",
49
+ "detail": "high"
50
+ }
51
+ }
52
+ ]
53
+ }
54
+ ],
55
+ "tools": [
56
+ {
57
+ "type": "function",
58
+ "function": {
59
+ "name": "list_files",
60
+ "description": "List files in a directory",
61
+ "parameters": {
62
+ "type": "object",
63
+ "properties": {
64
+ "path": {
65
+ "type": "string",
66
+ "description": "The directory path to list"
67
+ }
68
+ },
69
+ "required": ["path"]
70
+ }
71
+ }
72
+ },
73
+ {
74
+ "type": "function",
75
+ "function": {
76
+ "name": "read_file",
77
+ "description": "Read the contents of a file",
78
+ "parameters": {
79
+ "type": "object",
80
+ "properties": {
81
+ "path": {
82
+ "type": "string",
83
+ "description": "The file path to read"
84
+ }
85
+ },
86
+ "required": ["path"]
87
+ }
88
+ }
89
+ }
90
+ ],
91
+ "tool_choice": "auto",
92
+ "temperature": 0.7,
93
+ "top_p": 1.0,
94
+ "max_tokens": 4096,
95
+ "frequency_penalty": 0.0,
96
+ "presence_penalty": 0.0,
97
+ "stop": ["\n\n---"],
98
+ "stream": false,
99
+
100
+ "__note_no_model_field": "Unlike vanilla OpenAI, there is NO 'model' field in the body. The model is determined by the deployment name in the URL path.",
101
+ "__note_api_versioning": "api-version is a required query parameter, not a body field.",
102
+ "__note_additional_fields": "Azure also supports: data_sources (for Azure AI Search RAG), enhancements (for vision), and azure-specific response_format options."
103
+ }
@@ -0,0 +1,91 @@
1
+ {
2
+ "__comment": "Azure OpenAI response is identical to OpenAI format with some additional Azure-specific fields",
3
+
4
+ "id": "chatcmpl-abc123def456",
5
+ "object": "chat.completion",
6
+ "created": 1711234567,
7
+ "model": "gpt-4o",
8
+ "choices": [
9
+ {
10
+ "index": 0,
11
+ "message": {
12
+ "role": "assistant",
13
+ "content": "The diagram shows a microservices architecture with three main components..."
14
+ },
15
+ "finish_reason": "stop",
16
+ "content_filter_results": {
17
+ "hate": {
18
+ "filtered": false,
19
+ "severity": "safe"
20
+ },
21
+ "self_harm": {
22
+ "filtered": false,
23
+ "severity": "safe"
24
+ },
25
+ "sexual": {
26
+ "filtered": false,
27
+ "severity": "safe"
28
+ },
29
+ "violence": {
30
+ "filtered": false,
31
+ "severity": "safe"
32
+ }
33
+ }
34
+ }
35
+ ],
36
+ "usage": {
37
+ "prompt_tokens": 1245,
38
+ "completion_tokens": 89,
39
+ "total_tokens": 1334
40
+ },
41
+ "system_fingerprint": "fp_abc123",
42
+
43
+ "__comment_azure_additions": "Azure adds content_filter_results on every choice and prompt_filter_results at the top level. These are NOT present in vanilla OpenAI responses.",
44
+ "prompt_filter_results": [
45
+ {
46
+ "prompt_index": 0,
47
+ "content_filter_results": {
48
+ "hate": {
49
+ "filtered": false,
50
+ "severity": "safe"
51
+ },
52
+ "self_harm": {
53
+ "filtered": false,
54
+ "severity": "safe"
55
+ },
56
+ "sexual": {
57
+ "filtered": false,
58
+ "severity": "safe"
59
+ },
60
+ "violence": {
61
+ "filtered": false,
62
+ "severity": "safe"
63
+ }
64
+ }
65
+ }
66
+ ],
67
+
68
+ "__comment_tool_call_response": "Tool calls are identical to vanilla OpenAI format:",
69
+ "__tool_call_example": {
70
+ "choices": [
71
+ {
72
+ "index": 0,
73
+ "message": {
74
+ "role": "assistant",
75
+ "content": null,
76
+ "tool_calls": [
77
+ {
78
+ "id": "call_xyz789",
79
+ "type": "function",
80
+ "function": {
81
+ "name": "read_file",
82
+ "arguments": "{\"path\": \"README.md\"}"
83
+ }
84
+ }
85
+ ]
86
+ },
87
+ "finish_reason": "tool_calls"
88
+ }
89
+ ]
90
+ }
91
+ }