lemura 1.0.0 → 1.4.0
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 +162 -0
- package/README.md +17 -4
- package/dist/adapters/index.d.mts +2 -3
- package/dist/adapters/index.d.ts +2 -3
- package/dist/adapters/index.js +15 -7
- package/dist/adapters/index.js.map +1 -1
- package/dist/adapters/index.mjs +15 -7
- package/dist/adapters/index.mjs.map +1 -1
- package/dist/{adapters-BnG0LEYD.d.mts → adapters-BhTAnrOM.d.mts} +160 -2
- package/dist/{adapters-BSkhv5ac.d.ts → adapters-CVcfWf85.d.ts} +160 -2
- package/dist/agent-38El9_yp.d.ts +279 -0
- package/dist/agent-CJvmcAbT.d.mts +279 -0
- package/dist/context/index.d.mts +71 -8
- package/dist/context/index.d.ts +71 -8
- package/dist/context/index.js +75 -4
- package/dist/context/index.js.map +1 -1
- package/dist/context/index.mjs +74 -5
- package/dist/context/index.mjs.map +1 -1
- package/dist/index.d.mts +557 -33
- package/dist/index.d.ts +557 -33
- package/dist/index.js +2526 -258
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2517 -259
- package/dist/index.mjs.map +1 -1
- package/dist/skills/index.d.mts +92 -3
- package/dist/skills/index.d.ts +92 -3
- package/dist/skills/index.js +138 -8
- package/dist/skills/index.js.map +1 -1
- package/dist/skills/index.mjs +138 -8
- package/dist/skills/index.mjs.map +1 -1
- package/dist/skills-Y6D7zSSw.d.mts +66 -0
- package/dist/skills-Y6D7zSSw.d.ts +66 -0
- package/dist/tools/index.d.mts +125 -5
- package/dist/tools/index.d.ts +125 -5
- package/dist/tools/index.js +278 -7
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/index.mjs +277 -8
- package/dist/tools/index.mjs.map +1 -1
- package/dist/types/index.d.mts +18 -69
- package/dist/types/index.d.ts +18 -69
- package/dist/types/index.js +21 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/index.mjs +19 -1
- package/dist/types/index.mjs.map +1 -1
- package/package.json +6 -1
- package/dist/skills-wc8S-OvC.d.mts +0 -14
- package/dist/skills-wc8S-OvC.d.ts +0 -14
- package/dist/storage-BGu4Loao.d.ts +0 -121
- package/dist/storage-DMcliVVj.d.mts +0 -121
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,168 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.4.0] - 2026-03-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Fixed/Dynamic skill loading strategy** (`ISkill.strategy`): Skills now support a `strategy` field — `'fixed'` (default, always active, fully backward-compatible) or `'dynamic'` (opt-in pool, activated by name or tag). This replaces the previous always-on behavior with a market-style loading model.
|
|
13
|
+
|
|
14
|
+
- **`SkillInjector.enableSkill(name)`** / **`disableSkill(name)`**: Enable or disable a named dynamic skill at runtime.
|
|
15
|
+
|
|
16
|
+
- **`SkillInjector.enableByTags(tags)`** / **`disableByTags(tags)`**: Bulk-enable or disable dynamic skills whose `tags` array intersects with the given set.
|
|
17
|
+
|
|
18
|
+
- **`SkillInjector.getActiveSkills()`**: Returns the currently active skill set (fixed skills always included; dynamic skills only when enabled).
|
|
19
|
+
|
|
20
|
+
- **`SkillInjector.getRequiredTools()`**: Returns the union of `requiredTools` from all currently active skills. Host applications can use this to expose only the tools that the active skill set actually depends on.
|
|
21
|
+
|
|
22
|
+
- **`SkillInjector.getAll()`**: Returns all registered skills regardless of activation state.
|
|
23
|
+
|
|
24
|
+
- **`ISkill.requiredTools?: string[]`**: New optional field declaring which tool names a skill depends on. Surfaced via `getRequiredTools()`.
|
|
25
|
+
|
|
26
|
+
- **`ISkill.tags?: string[]`**: New optional field for arbitrary tag-based dynamic skill selection.
|
|
27
|
+
|
|
28
|
+
- **`ISkill.enabled?: boolean`**: Activation flag for `dynamic` skills. Defaults to `false` — dynamic skills must be explicitly enabled. Ignored on fixed skills.
|
|
29
|
+
|
|
30
|
+
- **`ISkill.content?: string`**: New optional field accepting the full skill body (without frontmatter). Used as the `standard`-level content when `standard` is absent, enabling the `{ content: markdownBody }` shorthand pattern documented in the skills guide.
|
|
31
|
+
|
|
32
|
+
- **`ISkill.tier` is now optional**: Was incorrectly required. The injection block header shows `'standard'` when `tier` is absent — no breaking change to runtime behavior.
|
|
33
|
+
|
|
34
|
+
- **`SessionConfig.activeDynamicSkills?: string[]`**: Names of dynamic skills to enable automatically at session construction.
|
|
35
|
+
|
|
36
|
+
- **`SessionConfig.activeDynamicTags?: string[]`**: Tags used to bulk-enable dynamic skills at session construction.
|
|
37
|
+
|
|
38
|
+
- **`TraceEvent.type: 'skill'`**: New trace type emitted during `session_init` — one `skill_load` event per active skill, carrying `name`, `version`, `strategy`, `inject`, `priority`, `tags`, and `requiredTools`.
|
|
39
|
+
|
|
40
|
+
- **`SessionManager.skills` accessor**: Public getter returning the session's `SkillInjector` instance for runtime skill management (`session.skills.enableSkill(...)`, `session.skills.getRequiredTools()`, etc.).
|
|
41
|
+
|
|
42
|
+
- **`SessionManager.tools` accessor**: Public getter returning the session's `ToolRegistry` instance for runtime tool management (`session.tools.register(...)`, `session.tools.unregister(...)`, `session.tools.getAll()`). Previously the registry was private — docs referenced this API but it wasn't accessible.
|
|
43
|
+
|
|
44
|
+
- **`session_init` trace now includes skill summary**: The `system / session_init` trace metadata includes `skills: { total, active, fixed, dynamic }` counts.
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- `SkillInjector.getSkillsForInjection()` — now returns only **active** skills (fixed + enabled dynamic). Previously returned all registered skills regardless of state.
|
|
49
|
+
- `SkillInjector._pickContent()` — fallback chain now includes `content` field between `standard` and `description`, fixing the silent empty-injection bug when skills were passed via `{ content: '...' }`.
|
|
50
|
+
- `SkillInjector.buildInjectionBlock()` — tier label in block header now falls back to `'standard'` instead of rendering as `undefined`.
|
|
51
|
+
|
|
52
|
+
### Fixed
|
|
53
|
+
|
|
54
|
+
- **Silent empty skill injection**: When a skill was constructed with only a `content` field (the `{ content: markdownBody }` shorthand), none of `nano/micro/standard` were set, causing `_pickContent` to return `description` (often empty) — the model never saw the skill content. Fixed by adding `content` to the resolution chain.
|
|
55
|
+
- **`ISkill.tier` rendering as `undefined`**: The injection block header `[Skill: name (Tier: undefined)]` is now `[Skill: name (Tier: standard)]` when `tier` is absent.
|
|
56
|
+
|
|
57
|
+
### Documentation
|
|
58
|
+
|
|
59
|
+
- `skills-system.md` — Fully rewritten to document `strategy: 'fixed' | 'dynamic'`, the `requiredTools` / `tags` fields, `session.skills` accessor, and the `activeDynamicSkills` / `activeDynamicTags` config options. Removed references to non-existent `autodiscoverTools` from Option 3.
|
|
60
|
+
- `tool-discovery.md` — Removed references to `session.on('tools:discovered')` (EventEmitter API, not implemented). Documented correct tool registration patterns and the `"lemura"` package.json convention.
|
|
61
|
+
- `tools-and-skills.md` — Fixed `session.tools.list()` → `session.tools.getAll()` (correct `ToolRegistry` method name).
|
|
62
|
+
- `session-config/tools-media-settings.md` — Removed non-existent `autodiscoverTools` config option; replaced with the correct manual import pattern. Fixed `session.tools.list()` → `session.tools.getAll()`.
|
|
63
|
+
- `getting-started/error-handling.md` — `session.tools.register()` example now works via the new `session.tools` public accessor.
|
|
64
|
+
|
|
65
|
+
> **Note:** Several other doc files (`observability.md`, `sandwich-compression.md`, `max-steps.md`, etc.) reference a `session.on(event, handler)` EventEmitter API that was planned but never implemented. These files are flagged for a follow-up documentation pass to replace with the `onTrace` callback pattern.
|
|
66
|
+
|
|
67
|
+
## [1.3.0] - 2026-03-13
|
|
68
|
+
|
|
69
|
+
### Added
|
|
70
|
+
|
|
71
|
+
- **`SummaryInjectionStrategy`** (`src/context/SummaryInjectionStrategy.ts`): New built-in context strategy that re-injects `ctx.compressionSummary` as a system turn before every provider call — ensuring the model always sees what was compressed. Idempotent (updates in-place on repeated runs). Configurable `priority` and `label`. Pair with `SandwichCompressionStrategy` or `HistoryCompressionStrategy`.
|
|
72
|
+
|
|
73
|
+
- **`SessionManager.setPlan(steps, strategy?)`**: New public method to register a `ContinuationPlan` before a `run()` call. The plan is stored in `context.metadata['continuationPlan']`, injected as a status block before every ReAct iteration, and survives context compression. Supports `'sequential'`, `'parallel'`, and `'conditional'` strategies.
|
|
74
|
+
|
|
75
|
+
- **`SessionManager.setGoal(goal)`**: New public method to manually set the agent's goal (statement, sub-goal decomposition, success criteria) without the automatic mini-planning LLM call. Goal is stored in `context.metadata['goal']`.
|
|
76
|
+
|
|
77
|
+
- **Goal mini-planning step**: When `enableGoalPlanning: true` and no manual goal is set, `run()` and `stream()` automatically make one LLM call before the first iteration to decompose the user's message into sub-goals and success criteria (stored in `GoalInjector` and `context.metadata['goal']`).
|
|
78
|
+
|
|
79
|
+
- **`GoalInjector.getFormattedBlock()`**: New method returning just the `[CURRENT GOAL]` block string — used internally for `pre_turn` injection (fixes empty-message bug when `goalInjectionPosition: 'pre_turn'`).
|
|
80
|
+
|
|
81
|
+
- **`GoalInjector.shouldInjectThisTurn(turnIndex, compressionOccurred, injectionN)`**: Properly implements all three `goalInjectionFrequency` values (`'always'`, `'every_N_turns'`, `'on_compression'`).
|
|
82
|
+
|
|
83
|
+
- **`GoalInjector.updateDecomposition(subGoals, successCriteria?)`**: Update sub-goals and criteria after mini-planning.
|
|
84
|
+
|
|
85
|
+
- **`GoalInjector.markSubGoalDone(subGoal)`**: Mark a sub-goal as completed so it appears in the `[/CURRENT GOAL]` completed section on subsequent injections.
|
|
86
|
+
|
|
87
|
+
- **`SessionConfig.maxCompletionTokens`**: New config field controlling the `maxTokens` argument passed to each `complete()` call (default: `2_000`). Previously this was hardcoded to `1000`.
|
|
88
|
+
|
|
89
|
+
- **`SessionConfig.goalInjectionN`**: New config field for `goalInjectionFrequency: 'every_N_turns'` — controls how often the goal is re-injected (default: `3`).
|
|
90
|
+
|
|
91
|
+
- **`ContinuationStep.condition`**: New optional field `{ step: string; outputContains: string }` that gates a step's execution on a substring check of a prior step's output. When not met, the step (and all dependants) are automatically marked `skipped`.
|
|
92
|
+
|
|
93
|
+
- **`ContinuationPlanner` state management methods**: `markStepRunning()`, `markStepDone(stepId, output?)`, `markStepFailed()`, `markStepSkipped()`, `getReadySteps()`, `isComplete()`, `getOutput(key)`, `resolveInputs(step, baseArgs)`. Dependency failure propagation is now BFS-based and fully correct.
|
|
94
|
+
|
|
95
|
+
- **`outputKey` / `inputMapping` wiring**: When a `ContinuationStep` defines `outputKey`, its tool result is stored in `context.metadata['toolOutputs'][outputKey]`. When the next step defines `inputMapping`, lemura resolves the prior step's output and passes it to the tool's arguments automatically.
|
|
96
|
+
|
|
97
|
+
- **`ToolResponseProcessor` config** (`ToolResponseProcessorConfig`): Constructor now accepts `smallMaxTokens` (default: 200), `mediumMaxTokens` (default: 800), `largeMaxTokens` (default: 2000), and `budgetPercent`. The `compress()` method now uses smarter extractive (head+tail) and line-level strategies instead of a fixed 1000-char truncation. Soft-error detection now catches more patterns (`"error"`, `connection refused`, `timed out`, etc.).
|
|
98
|
+
|
|
99
|
+
- **`SkillInjector` token budget**: `buildInjectionBlock(position, tokenBudget?)` now accepts an optional `tokenBudget`. Skills are added in priority order until the budget would be exceeded; compact tier variants (`nano` → `micro` → `standard`) are preferred when budgeting.
|
|
100
|
+
|
|
101
|
+
- **`SandwichCompressionStrategy` config improvements**: `triggerThreshold` now has a default (0.80). New optional `summaryMaxTokens` field passed to the summarization LLM call. New optional `priority` field (default: 20) — priority is now configurable at construction time instead of hardcoded.
|
|
102
|
+
|
|
103
|
+
- **`HistoryCompressionStrategy` priority config**: `priority` is now configurable at construction time (default: 30).
|
|
104
|
+
|
|
105
|
+
- **`lemura/mcp` sub-export**: `MCPClient` and `MCPClientRegistry` are now available via `import ... from 'lemura/mcp'` in addition to the main entry point.
|
|
106
|
+
|
|
107
|
+
### Changed
|
|
108
|
+
|
|
109
|
+
- `SessionManager` — `buildSystemPrompt()` now accepts `iteration` parameter and correctly gates goal injection via `shouldInjectThisTurn()`. The continuation plan status block is now injected into the system prompt when `enableContinuationPlanning` is true.
|
|
110
|
+
- `SessionManager` — `buildMessages()` now correctly injects the goal for `pre_turn` position using `goalInjector.getFormattedBlock()` instead of `injectInto('')` (fixes empty system message bug).
|
|
111
|
+
- `SessionManager.reset()` — now also resets `totalTokens` and `continuationPlanner`.
|
|
112
|
+
- `GoalInjector.injectInto()` — now always appends the goal block to the given prompt string regardless of position (position logic moved to `shouldInjectThisTurn()` + caller). Sub-goals in/completed sections included.
|
|
113
|
+
- `SessionConfig.toolResponseProcessor` — type updated to accept `IToolResponseProcessor` (interface) for custom implementations; built-in `ToolResponseProcessor` class is used by default.
|
|
114
|
+
|
|
115
|
+
### Fixed
|
|
116
|
+
|
|
117
|
+
- **`goalInjectionPosition: 'pre_turn'` bug**: Previously `goalInjector.injectInto('')` returned an empty string for `pre_turn` position, causing an empty system message to be pushed into the message list. Fixed by using `getFormattedBlock()` directly.
|
|
118
|
+
- **Hardcoded `maxTokens: 1000`** in `complete()` calls inside `run()` and `stream()`: Now uses `config.maxCompletionTokens ?? 2_000`.
|
|
119
|
+
- **`goalInjectionFrequency: 'every_N_turns'` / `'on_compression'`** were defined as enum values but never checked. Now fully implemented via `GoalInjector.shouldInjectThisTurn()`.
|
|
120
|
+
- **`SandwichCompressionStrategy.triggerThreshold`** was required but now correctly defaults to `0.80` if omitted.
|
|
121
|
+
- **`ToolResponseProcessor.compress()`** no longer truncates error responses (preserves them verbatim so the model can react to errors).
|
|
122
|
+
|
|
123
|
+
### Documentation
|
|
124
|
+
|
|
125
|
+
- All references to non-existent `MaxTokensCompressionStrategy` replaced with `HistoryCompressionStrategy`.
|
|
126
|
+
- All `SandwichCompressionStrategy` constructor calls in docs now include the required `adapter` first argument.
|
|
127
|
+
- `continuation-planning.md` fully rewritten to match `setPlan()` API, `condition` field, `outputKey`/`inputMapping` behavior.
|
|
128
|
+
- `goal-planning.md` rewritten to accurately describe `setGoal()`, the mini-planning step, `goalInjectionFrequency` options, `goalInjectionN`, and sub-goal tracking.
|
|
129
|
+
- `advanced-execution.md` quick-reference updated with `HistoryCompressionStrategy` and correct strategy signatures.
|
|
130
|
+
- `session-config.md` production preset examples fixed (correct adapter args, removed non-existent classes).
|
|
131
|
+
|
|
132
|
+
## [1.2.0] - 2026-03-12
|
|
133
|
+
|
|
134
|
+
### Added
|
|
135
|
+
- **MCP Support** (`MCPClient.ts`, `MCPRegistry.ts`): Model Context Protocol support integrated. You can now register tools from remote MCP servers.
|
|
136
|
+
- **Improved Traces & Observability**: Session traces now include detailed metadata for token usage, execution budget consumption, and planning states for every turn.
|
|
137
|
+
- **Tool Firewall — fully wired** (`ToolFirewall.ts`): The ask/accept/deny policy layer is now fully integrated into the `SessionManager` ReAct loop. Parallel batches respect firewall decisions per-call. No external dependencies.
|
|
138
|
+
- **Standalone JSON Schema Validator** (`SchemaValidator.ts`): Tool parameter validation now enforces the tool's JSON Schema at runtime before execution. Supports `type`, `required`, `properties`, `additionalProperties`, `enum`, `const`, `minLength`/`maxLength`/`pattern` (string), `minimum`/`maximum`/`exclusiveMinimum`/`exclusiveMaximum` (number), `minItems`/`maxItems`/`items` (array), `minProperties`/`maxProperties` (object), and `allOf`/`anyOf`/`oneOf`/`not` composition — zero external dependencies.
|
|
139
|
+
- **Tool execution timeout enforcement**: Every `ToolRegistry.execute()` call now races against a configurable timeout (`toolRegistryTimeoutMs`, default 30 s) via `Promise.race`. Throws `LemuraToolTimeoutError` on expiry.
|
|
140
|
+
- **Tool execution budget** (`ToolExecutionBudget` type + wired in `SessionManager`): Per-session and per-tool call quotas (`maxCallsPerSession`, `maxCallsPerTool`) and a concurrency cap (`maxConcurrentCalls`) are now enforced in the ReAct loop.
|
|
141
|
+
- **Parallel tool calls** (`parallelToolCalls: boolean`): When enabled, independent tool calls within a single assistant turn are executed in parallel via `Promise.all`, batched by `maxConcurrentCalls`. Falls back to sequential execution when disabled (default).
|
|
142
|
+
- **maxSteps guard wired**: `StepCounter` is now active in the ReAct loop. When `toolCallCount >= maxSteps`, tool definitions are removed from the provider payload and a forced-conclusion prompt + `FinalResponseFormatter` structure is injected.
|
|
143
|
+
- **Tool Response Compression wired**: `ToolResponseProcessor` is now applied to every tool result in the loop. Large/oversized responses are compressed before being appended to the context.
|
|
144
|
+
- **Goal Injection wired** (`enableGoalPlanning: true`): When enabled, a `GoalInjector` is initialised on the first `run()` call and injects the `[CURRENT GOAL]` block into the system prompt (or as a `pre_turn` message) on every iteration.
|
|
145
|
+
- **`SessionManager.stream()`**: New `AsyncIterable<string>` method streams the final LLM response token-by-token. Tool calls within the loop are completed synchronously before streaming the conclusion.
|
|
146
|
+
- **`SessionManager.reset()`**: New method clears conversation history, resets iteration counters, and clears tool execution budget tallies without losing the adapter or config.
|
|
147
|
+
- **`ToolRegistry.unregister()`**: New method to remove a registered tool by name at runtime.
|
|
148
|
+
- **`ToolRegistry.executeParallel()`**: New method for executing a batch of named tool calls in parallel with per-call error isolation.
|
|
149
|
+
|
|
150
|
+
### Changed
|
|
151
|
+
- `ToolRegistry.execute()` — now validates params, enforces timeout, and wraps errors in `LemuraError` subclasses instead of raw `Error`.
|
|
152
|
+
- `ToolRegistry` constructor — accepts an optional `ToolRegistryOptions` second argument (`defaultTimeoutMs`).
|
|
153
|
+
- `SessionConfig` — new fields: `toolExecutionBudget`, `parallelToolCalls`, `toolRegistryTimeoutMs`.
|
|
154
|
+
- `ToolFirewallRule` and `ToolFirewallConfig` — all fields now have TSDoc inline documentation.
|
|
155
|
+
|
|
156
|
+
### Fixed
|
|
157
|
+
- Tool errors in the ReAct loop now correctly distinguish timeout (`LemuraToolTimeoutError`) from execution failures, with accurate structured log output and hints.
|
|
158
|
+
- `any`-typed variables in `ToolRegistry.execute()` replaced with typed `LemuraError` subclasses for full strict-mode compliance.
|
|
159
|
+
|
|
160
|
+
## [1.1.0] - 2026-03-08
|
|
161
|
+
|
|
162
|
+
### Added
|
|
163
|
+
- `MediaBridge` — unified API for ASR, TTS, Vision, and Image Generation over `IProviderAdapter`.
|
|
164
|
+
- Built-in media tools (`media_transcribe`, `media_synthesize`, `media_describe_image`, `media_generate_image`) enabled via `SessionConfig.media.enableTools`.
|
|
165
|
+
- `ToolFirewall` — ask/accept/deny rule-based gating for tool calls (`SessionConfig.toolFirewall`).
|
|
166
|
+
- Advanced execution classes: `StepCounter`, `GoalInjector`, `ContinuationPlanner`, `FinalResponseFormatter`, `ToolResponseProcessor` (in `src/agent/execution/`).
|
|
167
|
+
- `ToolExecutionBudget` type for per-session and per-tool call quotas.
|
|
168
|
+
|
|
169
|
+
|
|
8
170
|
## [1.0.0] - 2026-03-07
|
|
9
171
|
|
|
10
172
|
### Added
|
package/README.md
CHANGED
|
@@ -5,14 +5,26 @@
|
|
|
5
5
|
**A provider-agnostic, premium agentic AI runtime for the modern web.**
|
|
6
6
|
|
|
7
7
|
[](https://www.npmjs.com/package/lemura)
|
|
8
|
-
[](
|
|
9
|
-
[](./LICENSE)
|
|
9
|
+
[](https://lemura.makix.fr)
|
|
10
|
+
[](https://github.com/rzafiamy/lemura/actions)
|
|
11
|
+
[](https://codecov.io/gh/rzafiamy/lemura)
|
|
11
12
|
|
|
12
13
|
---
|
|
13
14
|
|
|
14
15
|
`lemura` is a robust, provider-agnostic npm package designed to encapsulate a full agentic AI runtime. It simplifies the complex orchestration of LLMs, tools, and context management into a single, cohesive interface.
|
|
15
16
|
|
|
17
|
+
### ✨ Key Features in v1.4.0
|
|
18
|
+
- **🧠 Dynamic Skill Market**: Switch skills on/off at runtime via tags, names, or tool dependencies.
|
|
19
|
+
- **🗺️ Continuation Planning**: Multi-step tool chains with parallel execution and conditional logic.
|
|
20
|
+
- **🎯 Intelligent Goal Maintenance**: LLM-powered sub-goal decomposition and status tracking.
|
|
21
|
+
- **🔌 MCP Support**: Native Model Context Protocol integration for connecting to external tool servers.
|
|
22
|
+
- **🛡️ Tool Firewall**: Fully integrated ask/accept/deny policy layer for security.
|
|
23
|
+
- **⚡ Parallel Tool Calls**: Execute independent tools concurrently for reduced latency.
|
|
24
|
+
- **🧹 Summary Injection**: ensures the model never "forgets" what was compressed away.
|
|
25
|
+
- **📊 Enhanced Observability**: Detailed tracing, token tracking, and execution budget enforcement.
|
|
26
|
+
- **🌊 Native Streaming**: Token-by-token completion for smooth user experiences.
|
|
27
|
+
|
|
16
28
|
## 🚀 Install
|
|
17
29
|
|
|
18
30
|
```bash
|
|
@@ -76,12 +88,13 @@ main();
|
|
|
76
88
|
|
|
77
89
|
## 🧠 Core Concepts
|
|
78
90
|
|
|
79
|
-
Explore the architecture and advanced capabilities of `lemura
|
|
91
|
+
Explore the architecture and advanced capabilities of `lemura` at [lemura.makix.fr](https://lemura.makix.fr) or browse the local guides:
|
|
80
92
|
|
|
81
93
|
- 🏁 [**Getting Started**](./docs/guides/getting-started.md) — Fundamental setup and concepts.
|
|
82
94
|
- 🧹 [**Context Management**](./docs/guides/context-management.md) — Advanced compression strategies.
|
|
83
95
|
- 🔌 [**Adapters**](./docs/guides/adapters.md) — Connecting to OpenAI, Groq, Anthropic, and more.
|
|
84
96
|
- 🛠️ [**Tools and Skills**](./docs/guides/tools-and-skills.md) — Extending agent capabilities.
|
|
97
|
+
- 🎛️ [**Media Bridge**](./docs/guides/media-bridge.md) — ASR, TTS, vision, and image generation.
|
|
85
98
|
- ⚡ [**Advanced Execution**](./docs/guides/advanced-execution.md) — Goal planning and continuation.
|
|
86
99
|
|
|
87
100
|
## 📦 API Overview
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '../storage-DMcliVVj.mjs';
|
|
1
|
+
import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, T as TranscriptionRequest, d as TranscriptionResponse, e as SynthesisRequest, A as AudioChunk, V as VisionRequest, f as VisionResponse, g as ImageGenRequest, h as ImageGenResponse } from '../adapters-BhTAnrOM.mjs';
|
|
3
2
|
import '../rag-La_Bo-J8.mjs';
|
|
4
3
|
import '../logger-DxvKliuk.mjs';
|
|
5
4
|
|
|
@@ -20,7 +19,7 @@ interface OpenAICompatibleAdapterConfig {
|
|
|
20
19
|
*/
|
|
21
20
|
declare class OpenAICompatibleAdapter implements IProviderAdapter {
|
|
22
21
|
readonly name = "openai_compatible";
|
|
23
|
-
readonly version = "1.
|
|
22
|
+
readonly version = "1.2.0";
|
|
24
23
|
private baseUrl;
|
|
25
24
|
private apiKey;
|
|
26
25
|
private defaultModel;
|
package/dist/adapters/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import '../storage-BGu4Loao.js';
|
|
1
|
+
import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, T as TranscriptionRequest, d as TranscriptionResponse, e as SynthesisRequest, A as AudioChunk, V as VisionRequest, f as VisionResponse, g as ImageGenRequest, h as ImageGenResponse } from '../adapters-CVcfWf85.js';
|
|
3
2
|
import '../rag-La_Bo-J8.js';
|
|
4
3
|
import '../logger-DxvKliuk.js';
|
|
5
4
|
|
|
@@ -20,7 +19,7 @@ interface OpenAICompatibleAdapterConfig {
|
|
|
20
19
|
*/
|
|
21
20
|
declare class OpenAICompatibleAdapter implements IProviderAdapter {
|
|
22
21
|
readonly name = "openai_compatible";
|
|
23
|
-
readonly version = "1.
|
|
22
|
+
readonly version = "1.2.0";
|
|
24
23
|
private baseUrl;
|
|
25
24
|
private apiKey;
|
|
26
25
|
private defaultModel;
|
package/dist/adapters/index.js
CHANGED
|
@@ -28,7 +28,7 @@ var LemuraAdapterError = class extends LemuraError {
|
|
|
28
28
|
// src/adapters/OpenAICompatibleAdapter.ts
|
|
29
29
|
var OpenAICompatibleAdapter = class {
|
|
30
30
|
name = "openai_compatible";
|
|
31
|
-
version = "1.
|
|
31
|
+
version = "1.2.0";
|
|
32
32
|
baseUrl;
|
|
33
33
|
apiKey;
|
|
34
34
|
defaultModel;
|
|
@@ -277,7 +277,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
277
277
|
const blob = new Blob([bytes], { type: request.mimeType });
|
|
278
278
|
const formData = new FormData();
|
|
279
279
|
formData.append("file", blob, "audio.webm");
|
|
280
|
-
formData.append("model", "whisper-1");
|
|
280
|
+
formData.append("model", request.model || "whisper-1");
|
|
281
281
|
if (request.language) formData.append("language", request.language);
|
|
282
282
|
const response = await this.fetchWithRetry(`${this.baseUrl}/audio/transcriptions`, {
|
|
283
283
|
method: "POST",
|
|
@@ -298,7 +298,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
298
298
|
const response = await this.fetchWithRetry(`${this.baseUrl}/audio/speech`, {
|
|
299
299
|
method: "POST",
|
|
300
300
|
body: JSON.stringify({
|
|
301
|
-
model: "tts-1",
|
|
301
|
+
model: request.model || "tts-1",
|
|
302
302
|
input: request.text,
|
|
303
303
|
voice: request.voiceId || "alloy",
|
|
304
304
|
response_format: request.format || "mp3"
|
|
@@ -321,7 +321,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
321
321
|
}
|
|
322
322
|
async describeImage(request) {
|
|
323
323
|
const payload = {
|
|
324
|
-
model: this.defaultModel,
|
|
324
|
+
model: request.model || this.defaultModel,
|
|
325
325
|
messages: [
|
|
326
326
|
{
|
|
327
327
|
role: "user",
|
|
@@ -353,15 +353,23 @@ var OpenAICompatibleAdapter = class {
|
|
|
353
353
|
method: "POST",
|
|
354
354
|
body: JSON.stringify({
|
|
355
355
|
prompt: request.prompt,
|
|
356
|
-
model: "dall-e-3",
|
|
356
|
+
model: request.model || "dall-e-3",
|
|
357
357
|
n: 1,
|
|
358
358
|
size: request.dimensions || "1024x1024"
|
|
359
359
|
})
|
|
360
360
|
});
|
|
361
361
|
const data = await response.json();
|
|
362
|
+
if (data?.error) {
|
|
363
|
+
throw new LemuraAdapterError(data.error.message || "Image generation failed", "IMAGE_GEN_ERROR");
|
|
364
|
+
}
|
|
365
|
+
const first = data?.data?.[0] || {};
|
|
366
|
+
const imageUrl = first.url || (first.b64_json ? `data:image/png;base64,${first.b64_json}` : null) || (first.image_url?.url || null);
|
|
367
|
+
if (!imageUrl) {
|
|
368
|
+
throw new LemuraAdapterError("Image generation returned no image URL or base64 payload", "IMAGE_GEN_EMPTY");
|
|
369
|
+
}
|
|
362
370
|
return {
|
|
363
|
-
imageUrl
|
|
364
|
-
revisedPrompt:
|
|
371
|
+
imageUrl,
|
|
372
|
+
revisedPrompt: first.revised_prompt
|
|
365
373
|
};
|
|
366
374
|
}
|
|
367
375
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/errors.ts","../../src/adapters/OpenAICompatibleAdapter.ts"],"names":[],"mappings":";;;AAMO,IAAM,WAAA,GAAN,cAA0B,KAAA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,YACI,OAAA,EACgB,IAAA,EACA,OAAA,EACA,KAAA,GAAkB,EAAC,EACrC;AACE,IAAA,KAAA,CAAM,OAAO,CAAA;AAJG,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EACpD;AACJ,CAAA;AAmBO,IAAM,kBAAA,GAAN,cAAiC,WAAA,CAAY;AAAA,EAChD,WAAA,CACI,SACA,IAAA,GAAO,eAAA,EACA,OACP,OAAA,EACA,KAAA,GAAkB,EAAC,EACrB;AACE,IAAA,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,KAAK,CAAA;AAJ5B,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAKP,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AAAA,EAChB;AACJ,CAAA;;;ACnBO,IAAM,0BAAN,MAA0D;AAAA,EACpD,IAAA,GAAO,mBAAA;AAAA,EACP,OAAA,GAAU,OAAA;AAAA,EAEX,OAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EAER,WAAA,CAAY,MAAA,GAAwC,EAAC,EAAG;AACpD,IAAA,IAAA,CAAK,OAAA,GAAA,CACD,MAAA,CAAO,OAAA,IACP,OAAA,CAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,eAAA,IACZ,2BAAA,EACF,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAEnB,IAAA,IAAA,CAAK,MAAA,GAAS,OAAO,MAAA,IAAU,OAAA,CAAQ,IAAI,cAAA,IAAkB,OAAA,CAAQ,IAAI,cAAA,IAAkB,EAAA;AAC3F,IAAA,IAAA,CAAK,YAAA,GAAe,OAAO,YAAA,IAAgB,OAAA,CAAQ,IAAI,YAAA,IAAgB,OAAA,CAAQ,IAAI,YAAA,IAAgB,eAAA;AAEnG,IAAA,IAAA,CAAK,cAAA,GAAiB,MAAA,CAAO,cAAA,IAAkB,EAAC;AAChD,IAAA,IAAA,CAAK,SAAA,GAAY,OAAO,OAAA,IAAW,GAAA;AACnC,IAAA,IAAA,CAAK,cAAc,MAAA,CAAO,KAAA,IAAS,EAAE,UAAA,EAAY,CAAA,EAAG,aAAa,GAAA,EAAK;AAAA,EAC1E;AAAA,EAEA,MAAc,cAAA,CAAe,GAAA,EAAa,IAAA,EAAsC;AAC5E,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,OAAO,QAAA,IAAY,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AAC5C,MAAA,IAAI;AACA,QAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,QAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,SAAS,CAAA;AAErE,QAAA,MAAM,OAAA,GAAkC;AAAA,UACpC,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,UACtC,GAAG,IAAA,CAAK;AAAA,SACZ;AAEA,QAAA,IAAI,KAAK,OAAA,EAAS;AACd,UAAA,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,IAAA,CAAK,OAAO,CAAA;AAAA,QACvC;AAGA,QAAA,IAAI,OAAA,CAAQ,cAAc,CAAA,KAAM,OAAA,EAAS;AACrC,UAAA,OAAO,QAAQ,cAAc,CAAA;AAAA,QACjC,CAAA,MAAA,IAAW,CAAC,OAAA,CAAQ,cAAc,CAAA,EAAG;AACjC,UAAA,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAAA,QAC9B;AAEA,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,UAC9B,GAAG,IAAA;AAAA,UACH,QAAQ,UAAA,CAAW,MAAA;AAAA,UACnB;AAAA,SACH,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,QAAA,IAAI,QAAA,CAAS,IAAI,OAAO,QAAA;AAGxB,QAAA,IAAA,CAAK,QAAA,CAAS,WAAW,GAAA,IAAO,QAAA,CAAS,WAAW,GAAA,KAAQ,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AAChG,UAAA,QAAA,EAAA;AACA,UAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,CAAY,WAAA,GAAc,KAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAC,CAAA;AACrE,UAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,KAAK,CAAC,CAAA;AACvD,UAAA;AAAA,QACJ;AAEA,QAAA,MAAM,YAAY,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AACtD,QAAA,IAAI,OAAA,GAAU,uDAAA;AACd,QAAA,IAAI,KAAA,GAAQ,CAAC,6DAA6D,CAAA;AAE1E,QAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AACzB,UAAA,OAAA,GAAU,2DAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,sFAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,KAAW,GAAA,EAAK;AAChC,UAAA,OAAA,GAAU,gDAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,uEAAA;AAAA,YACA,oEAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,KAAW,GAAA,EAAK;AAChC,UAAA,OAAA,GAAU,sBAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,qCAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ;AAEA,QAAA,MAAM,IAAI,kBAAA;AAAA,UACN,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,EAAA,EAAK,SAAS,CAAA,CAAA;AAAA,UACrC,YAAA;AAAA,UACA,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,MAAM,SAAA,EAAU;AAAA,UAC3C,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,MACJ,SAAS,GAAA,EAAK;AACV,QAAA,IAAI,GAAA,YAAe,oBAAoB,MAAM,GAAA;AAE7C,QAAA,IAAI,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AACxC,UAAA,QAAA,EAAA;AACA,UAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,CAAY,WAAA,GAAc,KAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAC,CAAA;AACrE,UAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,KAAK,CAAC,CAAA;AACvD,UAAA;AAAA,QACJ;AAEA,QAAA,MAAM,IAAI,kBAAA;AAAA,UACN,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E,eAAA;AAAA,UACA,GAAA;AAAA,UACA,4DAAA;AAAA,UACA;AAAA,YACI,iCAAA;AAAA,YACA,yDAAA;AAAA,YACA;AAAA;AACJ,SACJ;AAAA,MACJ;AAAA,IACJ;AACA,IAAA,MAAM,IAAI,kBAAA;AAAA,MACN,sBAAA;AAAA,MACA,aAAA;AAAA,MACA,MAAA;AAAA,MACA,mDAAA;AAAA,MACA,CAAC,kEAAkE;AAAA,KACvE;AAAA,EACJ;AAAA,EAEQ,gBAAgB,MAAA,EAA2D;AAC/E,IAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AACpB,IAAA,MAAM,CAAA,GAAI,OAAO,WAAA,EAAY;AAC7B,IAAA,IAAI,CAAA,KAAM,YAAA,IAAgB,CAAA,KAAM,WAAA,EAAa,OAAO,WAAA;AACpD,IAAA,IAAI,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,YAAA,EAAc,OAAO,YAAA;AACjD,IAAA,IAAI,CAAA,KAAM,gBAAA,IAAoB,CAAA,KAAM,OAAA,EAAS,OAAO,OAAA;AACpD,IAAA,OAAO,MAAA;AAAA,EACX;AAAA,EAEQ,aAAa,OAAA,EAAqC;AACtD,IAAA,MAAM,OAAA,GAAmC;AAAA,MACrC,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,YAAA;AAAA,MAC7B,UAAU,OAAA,CAAQ;AAAA,KACtB;AACA,IAAA,IAAI,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAW,OAAA,CAAQ,aAAa,OAAA,CAAQ,SAAA;AAClE,IAAA,IAAI,OAAA,CAAQ,WAAA,KAAgB,MAAA,EAAW,OAAA,CAAQ,cAAc,OAAA,CAAQ,WAAA;AACrE,IAAA,IAAI,OAAA,CAAQ,aAAA,EAAe,MAAA,EAAQ,OAAA,CAAQ,OAAO,OAAA,CAAQ,aAAA;AAC1D,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,CAAQ,MAAA,GAAS,IAAA;AAErC,IAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA,EAAG;AAC3C,MAAA,OAAA,CAAQ,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,QACpC,IAAA,EAAM,UAAA;AAAA,QACN,QAAA,EAAU;AAAA,UACN,MAAM,CAAA,CAAE,IAAA;AAAA,UACR,aAAa,CAAA,CAAE,WAAA;AAAA,UACf,YAAY,CAAA,CAAE;AAAA;AAClB,OACJ,CAAE,CAAA;AAAA,IACN;AAEA,IAAA,OAAO,OAAA;AAAA,EACX;AAAA,EAEA,MAAM,SAAS,OAAA,EAAyD;AACpE,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,OAAO,CAAA;AAEzC,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,GAAU,CAAC,CAAA;AAC/B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,MAAM,IAAI,kBAAA,CAAmB,0CAAA,EAA4C,kBAAA,EAAoB,IAAI,CAAA;AAAA,IACrG;AAEA,IAAA,MAAM,UAAU,MAAA,CAAO,OAAA;AACvB,IAAA,IAAI,SAAA;AAEJ,IAAA,IAAI,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,UAAA,CAAW,SAAS,CAAA,EAAG;AACrD,MAAA,SAAA,GAAY,OAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,CAAC,EAAA,MAAa;AAAA,QAC7C,IAAI,EAAA,CAAG,EAAA;AAAA,QACP,IAAA,EAAM,GAAG,QAAA,CAAS,IAAA;AAAA,QAClB,SAAA,EAAW,GAAG,QAAA,CAAS;AAAA,OAC3B,CAAE,CAAA;AAAA,IACN;AAEA,IAAA,OAAO;AAAA,MACH,OAAA,EAAS,QAAQ,OAAA,IAAW,EAAA;AAAA,MAC5B,SAAA;AAAA,MACA,YAAA,EAAc,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,aAAa,CAAA;AAAA,MACvD,KAAA,EAAO;AAAA,QACH,YAAA,EAAc,IAAA,CAAK,KAAA,EAAO,aAAA,IAAiB,CAAA;AAAA,QAC3C,gBAAA,EAAkB,IAAA,CAAK,KAAA,EAAO,iBAAA,IAAqB,CAAA;AAAA,QACnD,WAAA,EAAa,IAAA,CAAK,KAAA,EAAO,YAAA,IAAgB;AAAA,OAC7C;AAAA,MACA,WAAA,EAAa;AAAA,KACjB;AAAA,EACJ;AAAA,EAEA,OAAO,OAAO,OAAA,EAA4D;AACtE,IAAA,MAAM,OAAA,GAAU,KAAK,YAAA,CAAa,EAAE,GAAG,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAE9D,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,IAAA,EAAM;AAChB,MAAA,MAAM,IAAI,kBAAA,CAAmB,uBAAA,EAAyB,cAAc,CAAA;AAAA,IACxE;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,CAAY,OAAO,CAAA;AACvC,IAAA,IAAI,MAAA,GAAS,EAAA;AAEb,IAAA,IAAI;AACA,MAAA,OAAO,IAAA,EAAM;AACT,QAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAK,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,QAAA,IAAI,IAAA,EAAM;AAEV,QAAA,MAAA,IAAU,QAAQ,MAAA,CAAO,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AAChD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAC/B,QAAA,MAAA,GAAS,KAAA,CAAM,KAAI,IAAK,EAAA;AAExB,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,UAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,UAAA,IAAI,CAAC,OAAA,IAAW,OAAA,KAAY,cAAA,EAAgB;AAC5C,UAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC9B,YAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA;AAC/B,YAAA,IAAI,IAAA;AACJ,YAAA,IAAI;AACA,cAAA,IAAA,GAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,YAC7B,SAAS,GAAA,EAAK;AACV,cAAA;AAAA,YACJ;AAEA,YAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,GAAU,CAAC,CAAA;AAC/B,YAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,YAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,EAAO,OAAA,IAAW,EAAA;AACvC,YAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,KAAA,EAAO,UAAA,GAAa,CAAC,CAAA;AAClD,YAAA,IAAI,aAAA;AAEJ,YAAA,IAAI,aAAA,EAAe;AACf,cAAA,aAAA,GAAgB;AAAA,gBACZ,IAAI,aAAA,CAAc,EAAA;AAAA,gBAClB,IAAA,EAAM,cAAc,QAAA,EAAU,IAAA;AAAA,gBAC9B,SAAA,EAAW,cAAc,QAAA,EAAU;AAAA,eACvC;AAAA,YACJ;AAEA,YAAA,MAAM,UAAA,GAAa,MAAA,CAAO,aAAA,KAAkB,IAAA,IAAQ,OAAO,aAAA,KAAkB,KAAA,CAAA;AAE7E,YAAA,MAAM;AAAA,cACF,KAAA;AAAA,cACA,QAAA,EAAU,UAAA;AAAA,cACV,GAAI,aAAA,IAAiB,EAAE,aAAA,EAAc;AAAA,cACrC,GAAI,cAAc,EAAE,YAAA,EAAc,KAAK,eAAA,CAAgB,MAAA,CAAO,aAAa,CAAA;AAAE,aACjF;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAA,SAAE;AACE,MAAA,MAAA,CAAO,WAAA,EAAY;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,eAAe,IAAA,EAAsB;AACjC,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAAA,EACpC;AAAA,EAEA,YAAA,GAA0B;AACtB,IAAA,OAAO;AAAA,MACH,cAAA,EAAgB,IAAA;AAAA,MAChB,aAAA,EAAe,IAAA;AAAA,MACf,aAAA,EAAe;AAAA,KACnB;AAAA,EACJ;AAAA,EAEA,MAAM,WAAA,GAAgC;AAClC,IAAA,IAAI;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,OAAA,CAAA,EAAW,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAClF,MAAA,OAAO,IAAA,CAAK,EAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,KAAA;AAAA,IACX;AAAA,EACJ;AAAA,EAEA,MAAM,WAAW,OAAA,EAA+D;AAC5E,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AAC7C,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,YAAA,CAAa,MAAM,CAAA;AAChD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,CAAa,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,KAAA,CAAM,CAAC,CAAA,GAAI,YAAA,CAAa,UAAA,CAAW,CAAC,CAAA;AAAA,IACxC;AACA,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,KAAK,GAAG,EAAE,IAAA,EAAM,OAAA,CAAQ,QAAA,EAAU,CAAA;AACzD,IAAA,MAAM,QAAA,GAAW,IAAI,QAAA,EAAS;AAC9B,IAAA,QAAA,CAAS,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,YAAY,CAAA;AAC1C,IAAA,QAAA,CAAS,MAAA,CAAO,SAAS,WAAW,CAAA;AACpC,IAAA,IAAI,QAAQ,QAAA,EAAU,QAAA,CAAS,MAAA,CAAO,UAAA,EAAY,QAAQ,QAAQ,CAAA;AAElE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,qBAAA,CAAA,EAAyB;AAAA,MAC/E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,QAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB;AAAA;AACpB,KACH,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO;AAAA,MACH,YAAY,IAAA,CAAK,IAAA;AAAA,MACjB,UAAA,EAAY,CAAA;AAAA;AAAA,MACZ,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,OAAA,CAAQ,QAAA,IAAY;AAAA,KACnD;AAAA,EACJ;AAAA,EAEA,OAAO,WAAW,OAAA,EAAsD;AACpE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,aAAA,CAAA,EAAiB;AAAA,MACvE,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,KAAA,EAAO,OAAA;AAAA,QACP,OAAO,OAAA,CAAQ,IAAA;AAAA,QACf,KAAA,EAAO,QAAQ,OAAA,IAAW,OAAA;AAAA,QAC1B,eAAA,EAAiB,QAAQ,MAAA,IAAU;AAAA,OACtC;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,IAAA,QAAY,IAAI,kBAAA,CAAmB,4BAA4B,cAAc,CAAA;AAE3F,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,IAAA,IAAI;AACA,MAAA,OAAO,IAAA,EAAM;AACT,QAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,QAAA,IAAI,IAAA,EAAM;AACV,QAAA,IAAI,KAAA,EAAO;AACP,UAAA,MAAM,SAAS,IAAI,WAAA,CAAY,QAAQ,CAAA,CAAE,OAAO,KAAK,CAAA;AACrD,UAAA,MAAM,EAAE,WAAA,EAAa,IAAA,CAAK,MAAM,CAAA,EAAE;AAAA,QACtC;AAAA,MACJ;AAAA,IACJ,CAAA,SAAE;AACE,MAAA,MAAA,CAAO,WAAA,EAAY;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,MAAM,cAAc,OAAA,EAAiD;AACjE,IAAA,MAAM,OAAA,GAAU;AAAA,MACZ,OAAO,IAAA,CAAK,YAAA;AAAA,MACZ,QAAA,EAAU;AAAA,QACN;AAAA,UACI,IAAA,EAAM,MAAA;AAAA,UACN,OAAA,EAAS;AAAA,YACL,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,OAAA,CAAQ,UAAU,qBAAA,EAAsB;AAAA,YAC9D;AAAA,cACI,IAAA,EAAM,WAAA;AAAA,cACN,SAAA,EAAW;AAAA,gBACP,GAAA,EAAK,CAAA,uBAAA,EAA0B,OAAA,CAAQ,WAAW,CAAA;AAAA;AACtD;AACJ;AACJ;AACJ;AACJ,KACJ;AAEA,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO;AAAA,MACH,WAAA,EAAa,IAAA,CAAK,OAAA,CAAQ,CAAC,EAAE,OAAA,CAAQ,OAAA;AAAA,MACrC,SAAS;AAAC;AAAA,KACd;AAAA,EACJ;AAAA,EAEA,MAAM,cAAc,OAAA,EAAqD;AACrE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,mBAAA,CAAA,EAAuB;AAAA,MAC7E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,KAAA,EAAO,UAAA;AAAA,QACP,CAAA,EAAG,CAAA;AAAA,QACH,IAAA,EAAM,QAAQ,UAAA,IAAc;AAAA,OAC/B;AAAA,KACJ,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO;AAAA,MACH,QAAA,EAAU,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,CAAE,GAAA;AAAA,MACvB,aAAA,EAAe,IAAA,CAAK,IAAA,CAAK,CAAC,CAAA,CAAE;AAAA,KAChC;AAAA,EACJ;AACJ","file":"index.js","sourcesContent":["/**\n * Base class for all custom errors thrown by lemura.\n *\n * @example\n * throw new LemuraError('Something went wrong', 'UNKNOWN_ERROR');\n */\nexport class LemuraError extends Error {\n /**\n * @param message - The error message\n * @param code - The error code for programmatic handling\n * @param problem - A clear description of the problem for the end user\n * @param hints - A list of suggestions to resolve the issue\n */\n constructor(\n message: string,\n public readonly code: string,\n public readonly problem?: string,\n public readonly hints: string[] = []\n ) {\n super(message);\n this.name = 'LemuraError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Error thrown when context exceeds max tokens and cannot be compressed further */\nexport class LemuraContextOverflowError extends LemuraError {\n constructor(message: string) {\n super(message, 'CONTEXT_OVERFLOW');\n this.name = 'LemuraContextOverflowError';\n }\n}\n\n/** Error thrown when a requested tool is not found in the registry */\nexport class LemuraToolNotFoundError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_NOT_FOUND');\n this.name = 'LemuraToolNotFoundError';\n }\n}\n\n/** Error thrown when an adapter encounters an API or formatting issue */\nexport class LemuraAdapterError extends LemuraError {\n constructor(\n message: string,\n code = 'ADAPTER_ERROR',\n public cause?: any,\n problem?: string,\n hints: string[] = []\n ) {\n super(message, code, problem, hints);\n this.name = 'LemuraAdapterError';\n }\n}\n\n/** Error thrown when a skill cannot be parsed or injected */\nexport class LemuraSkillInjectionError extends LemuraError {\n constructor(message: string) {\n super(message, 'SKILL_INJECTION_FAILED');\n this.name = 'LemuraSkillInjectionError';\n }\n}\n\n/** Error thrown when the ReAct loop exceeds the configured max iterations */\nexport class LemuraMaxIterationsError extends LemuraError {\n constructor(message: string) {\n super(message, 'MAX_ITERATIONS_EXCEEDED');\n this.name = 'LemuraMaxIterationsError';\n }\n}\n\n/** Error thrown when tool parameters fail JSON schema validation */\nexport class LemuraToolValidationError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_VALIDATION_FAILED');\n this.name = 'LemuraToolValidationError';\n }\n}\n\n/** Error thrown when a tool execute function exceeds its timeout */\nexport class LemuraToolTimeoutError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_TIMEOUT');\n this.name = 'LemuraToolTimeoutError';\n }\n}\n","import {\n IProviderAdapter,\n CompletionRequest,\n CompletionResponse,\n CompletionChunk,\n TranscriptionRequest,\n TranscriptionResponse,\n SynthesisRequest,\n AudioChunk,\n VisionRequest,\n VisionResponse,\n ImageGenRequest,\n ImageGenResponse,\n ModelInfo,\n LemuraAdapterError,\n} from '../types/index.js';\n\nexport interface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n}\n\nexport interface OpenAICompatibleAdapterConfig {\n baseUrl?: string;\n apiKey?: string;\n defaultModel?: string;\n defaultHeaders?: Record<string, string>;\n timeout?: number;\n retry?: RetryConfig;\n}\n\n/**\n * Reference implementation of an OpenAI-compatible provider adapter.\n */\nexport class OpenAICompatibleAdapter implements IProviderAdapter {\n readonly name = 'openai_compatible';\n readonly version = '1.0.0';\n\n private baseUrl: string;\n private apiKey: string;\n private defaultModel: string;\n private defaultHeaders: Record<string, string>;\n private timeoutMs: number;\n private retryConfig: RetryConfig;\n\n constructor(config: OpenAICompatibleAdapterConfig = {}) {\n this.baseUrl = (\n config.baseUrl ??\n process.env.LEMURA_BASE_URL ??\n process.env.OPENAI_BASE_URL ??\n 'https://api.openai.com/v1'\n ).replace(/\\/$/, '');\n\n this.apiKey = config.apiKey ?? process.env.LEMURA_API_KEY ?? process.env.OPENAI_API_KEY ?? '';\n this.defaultModel = config.defaultModel ?? process.env.LEMURA_MODEL ?? process.env.OPENAI_MODEL ?? 'gpt-3.5-turbo';\n\n this.defaultHeaders = config.defaultHeaders || {};\n this.timeoutMs = config.timeout || 30000;\n this.retryConfig = config.retry || { maxRetries: 2, baseDelayMs: 1000 };\n }\n\n private async fetchWithRetry(url: string, init: RequestInit): Promise<Response> {\n let attempts = 0;\n while (attempts <= this.retryConfig.maxRetries) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n ...this.defaultHeaders,\n };\n\n if (init.headers) {\n Object.assign(headers, init.headers);\n }\n\n // Don't set Content-Type if it's 'unset' (for FormData)\n if (headers['Content-Type'] === 'unset') {\n delete headers['Content-Type'];\n } else if (!headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n\n const response = await fetch(url, {\n ...init,\n signal: controller.signal,\n headers,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) return response;\n\n // Retry on 429 and 503\n if ((response.status === 429 || response.status === 503) && attempts < this.retryConfig.maxRetries) {\n attempts++;\n const delay = this.retryConfig.baseDelayMs * Math.pow(2, attempts - 1);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n const errorText = await response.text().catch(() => '');\n let problem = 'The server replied with an error during the API call.';\n let hints = ['Check the API documentation for the provider you are using.'];\n\n if (response.status === 401) {\n problem = 'Authentication failed. The API key is invalid or missing.';\n hints = [\n 'Ensure your API key is correctly configured in the adapter or environment variables.',\n 'Check if the API key has expired or been revoked.'\n ];\n } else if (response.status === 404) {\n problem = 'The requested resource or model was not found.';\n hints = [\n 'Verify that the baseUrl is correct (e.g., https://api.openai.com/v1).',\n 'Check if the model name is correct and available for your account.',\n 'Ensure you are not appending extra paths to the baseUrl.'\n ];\n } else if (response.status === 429) {\n problem = 'Rate limit exceeded.';\n hints = [\n 'Wait a few seconds before retrying.',\n 'Check your usage limits and billing status on the provider dashboard.'\n ];\n }\n\n throw new LemuraAdapterError(\n `HTTP ${response.status}: ${errorText}`,\n 'HTTP_ERROR',\n { status: response.status, body: errorText },\n problem,\n hints\n );\n } catch (err) {\n if (err instanceof LemuraAdapterError) throw err;\n\n if (attempts < this.retryConfig.maxRetries) {\n attempts++;\n const delay = this.retryConfig.baseDelayMs * Math.pow(2, attempts - 1);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw new LemuraAdapterError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n 'NETWORK_ERROR',\n err,\n 'A network error occurred while connecting to the provider.',\n [\n 'Check your internet connection.',\n 'Verify that the baseUrl is reachable from your network.',\n 'Check for proxy or firewall settings that might block the request.'\n ]\n );\n }\n }\n throw new LemuraAdapterError(\n 'Max retries exceeded',\n 'MAX_RETRIES',\n undefined,\n 'The request failed after multiple retry attempts.',\n ['Check if the provider service is down or experiencing high load.']\n );\n }\n\n private mapFinishReason(reason: string | null): CompletionResponse['finishReason'] {\n if (!reason) return 'stop';\n const r = reason.toLowerCase();\n if (r === 'tool_calls' || r === 'tool_call') return 'tool_call';\n if (r === 'length' || r === 'max_tokens') return 'max_tokens';\n if (r === 'content_filter' || r === 'error') return 'error';\n return 'stop';\n }\n\n private buildPayload(request: CompletionRequest): unknown {\n const payload: Record<string, unknown> = {\n model: request.model || this.defaultModel,\n messages: request.messages,\n };\n if (request.maxTokens !== undefined) payload.max_tokens = request.maxTokens;\n if (request.temperature !== undefined) payload.temperature = request.temperature;\n if (request.stopSequences?.length) payload.stop = request.stopSequences;\n if (request.stream) payload.stream = true;\n\n if (request.tools && request.tools.length > 0) {\n payload.tools = request.tools.map(t => ({\n type: 'function',\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n }\n }));\n }\n\n return payload;\n }\n\n async complete(request: CompletionRequest): Promise<CompletionResponse> {\n const payload = this.buildPayload(request);\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n const data = await response.json();\n const choice = data.choices?.[0];\n if (!choice) {\n throw new LemuraAdapterError('Invalid response format: missing choices', 'INVALID_RESPONSE', data);\n }\n\n const message = choice.message;\n let toolCalls;\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n toolCalls = message.tool_calls.map((tc: any) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n }));\n }\n\n return {\n content: message.content || '',\n toolCalls,\n finishReason: this.mapFinishReason(choice.finish_reason),\n usage: {\n promptTokens: data.usage?.prompt_tokens || 0,\n completionTokens: data.usage?.completion_tokens || 0,\n totalTokens: data.usage?.total_tokens || 0,\n },\n rawResponse: data\n };\n }\n\n async *stream(request: CompletionRequest): AsyncIterable<CompletionChunk> {\n const payload = this.buildPayload({ ...request, stream: true });\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n if (!response.body) {\n throw new LemuraAdapterError('Response body is null', 'STREAM_ERROR');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (trimmed.startsWith('data: ')) {\n const jsonStr = trimmed.slice(6);\n let data;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n continue;\n }\n\n const choice = data.choices?.[0];\n if (!choice) continue;\n\n const delta = choice.delta?.content || '';\n const toolCallBlock = choice.delta?.tool_calls?.[0];\n let toolCallDelta;\n\n if (toolCallBlock) {\n toolCallDelta = {\n id: toolCallBlock.id,\n name: toolCallBlock.function?.name,\n arguments: toolCallBlock.function?.arguments,\n };\n }\n\n const isFinished = choice.finish_reason !== null && choice.finish_reason !== undefined;\n\n yield {\n delta,\n finished: isFinished,\n ...(toolCallDelta && { toolCallDelta }),\n ...(isFinished && { finishReason: this.mapFinishReason(choice.finish_reason) })\n };\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n }\n\n getModelInfo(): ModelInfo {\n return {\n supportsVision: true,\n supportsTools: true,\n contextWindow: 128000\n };\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const resp = await this.fetchWithRetry(`${this.baseUrl}/models`, { method: 'GET' });\n return resp.ok;\n } catch {\n return false;\n }\n }\n\n async transcribe(request: TranscriptionRequest): Promise<TranscriptionResponse> {\n const binaryString = atob(request.audioBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const blob = new Blob([bytes], { type: request.mimeType });\n const formData = new FormData();\n formData.append('file', blob, 'audio.webm');\n formData.append('model', 'whisper-1');\n if (request.language) formData.append('language', request.language);\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/audio/transcriptions`, {\n method: 'POST',\n body: formData,\n headers: {\n 'Content-Type': 'unset'\n }\n });\n\n const data = await response.json();\n return {\n transcript: data.text,\n confidence: 1.0, // OpenAI doesn't return confidence in standard response\n language: data.language || request.language || 'en'\n };\n }\n\n async *synthesize(request: SynthesisRequest): AsyncIterable<AudioChunk> {\n const response = await this.fetchWithRetry(`${this.baseUrl}/audio/speech`, {\n method: 'POST',\n body: JSON.stringify({\n model: 'tts-1',\n input: request.text,\n voice: request.voiceId || 'alloy',\n response_format: request.format || 'mp3'\n })\n });\n\n if (!response.body) throw new LemuraAdapterError('No response body for TTS', 'STREAM_ERROR');\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n const binary = new TextDecoder('latin1').decode(value);\n yield { audioBase64: btoa(binary) };\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n async describeImage(request: VisionRequest): Promise<VisionResponse> {\n const payload = {\n model: this.defaultModel,\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: request.prompt || 'Describe this image' },\n {\n type: 'image_url',\n image_url: {\n url: `data:image/jpeg;base64,${request.imageBase64}`\n }\n }\n ]\n }\n ]\n };\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n const data = await response.json();\n return {\n description: data.choices[0].message.content,\n objects: [] // OpenAI doesn't return structured objects in standard vision call\n };\n }\n\n async generateImage(request: ImageGenRequest): Promise<ImageGenResponse> {\n const response = await this.fetchWithRetry(`${this.baseUrl}/images/generations`, {\n method: 'POST',\n body: JSON.stringify({\n prompt: request.prompt,\n model: 'dall-e-3',\n n: 1,\n size: request.dimensions || '1024x1024'\n })\n });\n\n const data = await response.json();\n return {\n imageUrl: data.data[0].url,\n revisedPrompt: data.data[0].revised_prompt\n };\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/errors.ts","../../src/adapters/OpenAICompatibleAdapter.ts"],"names":[],"mappings":";;;AAMO,IAAM,WAAA,GAAN,cAA0B,KAAA,CAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOnC,YACI,OAAA,EACgB,IAAA,EACA,OAAA,EACA,KAAA,GAAkB,EAAC,EACrC;AACE,IAAA,KAAA,CAAM,OAAO,CAAA;AAJG,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AACA,IAAA,IAAA,CAAA,OAAA,GAAA,OAAA;AACA,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAGhB,IAAA,IAAA,CAAK,IAAA,GAAO,aAAA;AACZ,IAAA,MAAA,CAAO,cAAA,CAAe,IAAA,EAAM,GAAA,CAAA,MAAA,CAAW,SAAS,CAAA;AAAA,EACpD;AACJ,CAAA;AAmBO,IAAM,kBAAA,GAAN,cAAiC,WAAA,CAAY;AAAA,EAChD,WAAA,CACI,SACA,IAAA,GAAO,eAAA,EACA,OACP,OAAA,EACA,KAAA,GAAkB,EAAC,EACrB;AACE,IAAA,KAAA,CAAM,OAAA,EAAS,IAAA,EAAM,OAAA,EAAS,KAAK,CAAA;AAJ5B,IAAA,IAAA,CAAA,KAAA,GAAA,KAAA;AAKP,IAAA,IAAA,CAAK,IAAA,GAAO,oBAAA;AAAA,EAChB;AACJ,CAAA;;;ACnBO,IAAM,0BAAN,MAA0D;AAAA,EACpD,IAAA,GAAO,mBAAA;AAAA,EACP,OAAA,GAAU,OAAA;AAAA,EAEX,OAAA;AAAA,EACA,MAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EAER,WAAA,CAAY,MAAA,GAAwC,EAAC,EAAG;AACpD,IAAA,IAAA,CAAK,OAAA,GAAA,CACD,MAAA,CAAO,OAAA,IACP,OAAA,CAAQ,GAAA,CAAI,eAAA,IACZ,OAAA,CAAQ,GAAA,CAAI,eAAA,IACZ,2BAAA,EACF,OAAA,CAAQ,KAAA,EAAO,EAAE,CAAA;AAEnB,IAAA,IAAA,CAAK,MAAA,GAAS,OAAO,MAAA,IAAU,OAAA,CAAQ,IAAI,cAAA,IAAkB,OAAA,CAAQ,IAAI,cAAA,IAAkB,EAAA;AAC3F,IAAA,IAAA,CAAK,YAAA,GAAe,OAAO,YAAA,IAAgB,OAAA,CAAQ,IAAI,YAAA,IAAgB,OAAA,CAAQ,IAAI,YAAA,IAAgB,eAAA;AAEnG,IAAA,IAAA,CAAK,cAAA,GAAiB,MAAA,CAAO,cAAA,IAAkB,EAAC;AAChD,IAAA,IAAA,CAAK,SAAA,GAAY,OAAO,OAAA,IAAW,GAAA;AACnC,IAAA,IAAA,CAAK,cAAc,MAAA,CAAO,KAAA,IAAS,EAAE,UAAA,EAAY,CAAA,EAAG,aAAa,GAAA,EAAK;AAAA,EAC1E;AAAA,EAEA,MAAc,cAAA,CAAe,GAAA,EAAa,IAAA,EAAsC;AAC5E,IAAA,IAAI,QAAA,GAAW,CAAA;AACf,IAAA,OAAO,QAAA,IAAY,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AAC5C,MAAA,IAAI;AACA,QAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,QAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,SAAS,CAAA;AAErE,QAAA,MAAM,OAAA,GAAkC;AAAA,UACpC,eAAA,EAAiB,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,UACtC,GAAG,IAAA,CAAK;AAAA,SACZ;AAEA,QAAA,IAAI,KAAK,OAAA,EAAS;AACd,UAAA,MAAA,CAAO,MAAA,CAAO,OAAA,EAAS,IAAA,CAAK,OAAO,CAAA;AAAA,QACvC;AAGA,QAAA,IAAI,OAAA,CAAQ,cAAc,CAAA,KAAM,OAAA,EAAS;AACrC,UAAA,OAAO,QAAQ,cAAc,CAAA;AAAA,QACjC,CAAA,MAAA,IAAW,CAAC,OAAA,CAAQ,cAAc,CAAA,EAAG;AACjC,UAAA,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAAA,QAC9B;AAEA,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,GAAA,EAAK;AAAA,UAC9B,GAAG,IAAA;AAAA,UACH,QAAQ,UAAA,CAAW,MAAA;AAAA,UACnB;AAAA,SACH,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,QAAA,IAAI,QAAA,CAAS,IAAI,OAAO,QAAA;AAGxB,QAAA,IAAA,CAAK,QAAA,CAAS,WAAW,GAAA,IAAO,QAAA,CAAS,WAAW,GAAA,KAAQ,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AAChG,UAAA,QAAA,EAAA;AACA,UAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,CAAY,WAAA,GAAc,KAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAC,CAAA;AACrE,UAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,KAAK,CAAC,CAAA;AACvD,UAAA;AAAA,QACJ;AAEA,QAAA,MAAM,YAAY,MAAM,QAAA,CAAS,MAAK,CAAE,KAAA,CAAM,MAAM,EAAE,CAAA;AACtD,QAAA,IAAI,OAAA,GAAU,uDAAA;AACd,QAAA,IAAI,KAAA,GAAQ,CAAC,6DAA6D,CAAA;AAE1E,QAAA,IAAI,QAAA,CAAS,WAAW,GAAA,EAAK;AACzB,UAAA,OAAA,GAAU,2DAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,sFAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,KAAW,GAAA,EAAK;AAChC,UAAA,OAAA,GAAU,gDAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,uEAAA;AAAA,YACA,oEAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ,CAAA,MAAA,IAAW,QAAA,CAAS,MAAA,KAAW,GAAA,EAAK;AAChC,UAAA,OAAA,GAAU,sBAAA;AACV,UAAA,KAAA,GAAQ;AAAA,YACJ,qCAAA;AAAA,YACA;AAAA,WACJ;AAAA,QACJ;AAEA,QAAA,MAAM,IAAI,kBAAA;AAAA,UACN,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,EAAA,EAAK,SAAS,CAAA,CAAA;AAAA,UACrC,YAAA;AAAA,UACA,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,MAAM,SAAA,EAAU;AAAA,UAC3C,OAAA;AAAA,UACA;AAAA,SACJ;AAAA,MACJ,SAAS,GAAA,EAAK;AACV,QAAA,IAAI,GAAA,YAAe,oBAAoB,MAAM,GAAA;AAE7C,QAAA,IAAI,QAAA,GAAW,IAAA,CAAK,WAAA,CAAY,UAAA,EAAY;AACxC,UAAA,QAAA,EAAA;AACA,UAAA,MAAM,KAAA,GAAQ,KAAK,WAAA,CAAY,WAAA,GAAc,KAAK,GAAA,CAAI,CAAA,EAAG,WAAW,CAAC,CAAA;AACrE,UAAA,MAAM,IAAI,OAAA,CAAQ,CAAA,OAAA,KAAW,UAAA,CAAW,OAAA,EAAS,KAAK,CAAC,CAAA;AACvD,UAAA;AAAA,QACJ;AAEA,QAAA,MAAM,IAAI,kBAAA;AAAA,UACN,2BAA2B,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AAAA,UAC3E,eAAA;AAAA,UACA,GAAA;AAAA,UACA,4DAAA;AAAA,UACA;AAAA,YACI,iCAAA;AAAA,YACA,yDAAA;AAAA,YACA;AAAA;AACJ,SACJ;AAAA,MACJ;AAAA,IACJ;AACA,IAAA,MAAM,IAAI,kBAAA;AAAA,MACN,sBAAA;AAAA,MACA,aAAA;AAAA,MACA,MAAA;AAAA,MACA,mDAAA;AAAA,MACA,CAAC,kEAAkE;AAAA,KACvE;AAAA,EACJ;AAAA,EAEQ,gBAAgB,MAAA,EAA2D;AAC/E,IAAA,IAAI,CAAC,QAAQ,OAAO,MAAA;AACpB,IAAA,MAAM,CAAA,GAAI,OAAO,WAAA,EAAY;AAC7B,IAAA,IAAI,CAAA,KAAM,YAAA,IAAgB,CAAA,KAAM,WAAA,EAAa,OAAO,WAAA;AACpD,IAAA,IAAI,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,YAAA,EAAc,OAAO,YAAA;AACjD,IAAA,IAAI,CAAA,KAAM,gBAAA,IAAoB,CAAA,KAAM,OAAA,EAAS,OAAO,OAAA;AACpD,IAAA,OAAO,MAAA;AAAA,EACX;AAAA,EAEQ,aAAa,OAAA,EAAqC;AACtD,IAAA,MAAM,OAAA,GAAmC;AAAA,MACrC,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,YAAA;AAAA,MAC7B,UAAU,OAAA,CAAQ;AAAA,KACtB;AACA,IAAA,IAAI,OAAA,CAAQ,SAAA,KAAc,MAAA,EAAW,OAAA,CAAQ,aAAa,OAAA,CAAQ,SAAA;AAClE,IAAA,IAAI,OAAA,CAAQ,WAAA,KAAgB,MAAA,EAAW,OAAA,CAAQ,cAAc,OAAA,CAAQ,WAAA;AACrE,IAAA,IAAI,OAAA,CAAQ,aAAA,EAAe,MAAA,EAAQ,OAAA,CAAQ,OAAO,OAAA,CAAQ,aAAA;AAC1D,IAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,CAAQ,MAAA,GAAS,IAAA;AAErC,IAAA,IAAI,OAAA,CAAQ,KAAA,IAAS,OAAA,CAAQ,KAAA,CAAM,SAAS,CAAA,EAAG;AAC3C,MAAA,OAAA,CAAQ,KAAA,GAAQ,OAAA,CAAQ,KAAA,CAAM,GAAA,CAAI,CAAA,CAAA,MAAM;AAAA,QACpC,IAAA,EAAM,UAAA;AAAA,QACN,QAAA,EAAU;AAAA,UACN,MAAM,CAAA,CAAE,IAAA;AAAA,UACR,aAAa,CAAA,CAAE,WAAA;AAAA,UACf,YAAY,CAAA,CAAE;AAAA;AAClB,OACJ,CAAE,CAAA;AAAA,IACN;AAEA,IAAA,OAAO,OAAA;AAAA,EACX;AAAA,EAEA,MAAM,SAAS,OAAA,EAAyD;AACpE,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,YAAA,CAAa,OAAO,CAAA;AAEzC,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,GAAU,CAAC,CAAA;AAC/B,IAAA,IAAI,CAAC,MAAA,EAAQ;AACT,MAAA,MAAM,IAAI,kBAAA,CAAmB,0CAAA,EAA4C,kBAAA,EAAoB,IAAI,CAAA;AAAA,IACrG;AAEA,IAAA,MAAM,UAAU,MAAA,CAAO,OAAA;AACvB,IAAA,IAAI,SAAA;AAEJ,IAAA,IAAI,OAAA,CAAQ,UAAA,IAAc,OAAA,CAAQ,UAAA,CAAW,SAAS,CAAA,EAAG;AACrD,MAAA,SAAA,GAAY,OAAA,CAAQ,UAAA,CAAW,GAAA,CAAI,CAAC,EAAA,MAAa;AAAA,QAC7C,IAAI,EAAA,CAAG,EAAA;AAAA,QACP,IAAA,EAAM,GAAG,QAAA,CAAS,IAAA;AAAA,QAClB,SAAA,EAAW,GAAG,QAAA,CAAS;AAAA,OAC3B,CAAE,CAAA;AAAA,IACN;AAEA,IAAA,OAAO;AAAA,MACH,OAAA,EAAS,QAAQ,OAAA,IAAW,EAAA;AAAA,MAC5B,SAAA;AAAA,MACA,YAAA,EAAc,IAAA,CAAK,eAAA,CAAgB,MAAA,CAAO,aAAa,CAAA;AAAA,MACvD,KAAA,EAAO;AAAA,QACH,YAAA,EAAc,IAAA,CAAK,KAAA,EAAO,aAAA,IAAiB,CAAA;AAAA,QAC3C,gBAAA,EAAkB,IAAA,CAAK,KAAA,EAAO,iBAAA,IAAqB,CAAA;AAAA,QACnD,WAAA,EAAa,IAAA,CAAK,KAAA,EAAO,YAAA,IAAgB;AAAA,OAC7C;AAAA,MACA,WAAA,EAAa;AAAA,KACjB;AAAA,EACJ;AAAA,EAEA,OAAO,OAAO,OAAA,EAA4D;AACtE,IAAA,MAAM,OAAA,GAAU,KAAK,YAAA,CAAa,EAAE,GAAG,OAAA,EAAS,MAAA,EAAQ,MAAM,CAAA;AAE9D,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,IAAI,CAAC,SAAS,IAAA,EAAM;AAChB,MAAA,MAAM,IAAI,kBAAA,CAAmB,uBAAA,EAAyB,cAAc,CAAA;AAAA,IACxE;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,IAAA,MAAM,OAAA,GAAU,IAAI,WAAA,CAAY,OAAO,CAAA;AACvC,IAAA,IAAI,MAAA,GAAS,EAAA;AAEb,IAAA,IAAI;AACA,MAAA,OAAO,IAAA,EAAM;AACT,QAAA,MAAM,EAAE,KAAA,EAAO,IAAA,EAAK,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,QAAA,IAAI,IAAA,EAAM;AAEV,QAAA,MAAA,IAAU,QAAQ,MAAA,CAAO,KAAA,EAAO,EAAE,MAAA,EAAQ,MAAM,CAAA;AAChD,QAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA;AAC/B,QAAA,MAAA,GAAS,KAAA,CAAM,KAAI,IAAK,EAAA;AAExB,QAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACtB,UAAA,MAAM,OAAA,GAAU,KAAK,IAAA,EAAK;AAC1B,UAAA,IAAI,CAAC,OAAA,IAAW,OAAA,KAAY,cAAA,EAAgB;AAC5C,UAAA,IAAI,OAAA,CAAQ,UAAA,CAAW,QAAQ,CAAA,EAAG;AAC9B,YAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,KAAA,CAAM,CAAC,CAAA;AAC/B,YAAA,IAAI,IAAA;AACJ,YAAA,IAAI;AACA,cAAA,IAAA,GAAO,IAAA,CAAK,MAAM,OAAO,CAAA;AAAA,YAC7B,SAAS,GAAA,EAAK;AACV,cAAA;AAAA,YACJ;AAEA,YAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,GAAU,CAAC,CAAA;AAC/B,YAAA,IAAI,CAAC,MAAA,EAAQ;AAEb,YAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,EAAO,OAAA,IAAW,EAAA;AACvC,YAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,KAAA,EAAO,UAAA,GAAa,CAAC,CAAA;AAClD,YAAA,IAAI,aAAA;AAEJ,YAAA,IAAI,aAAA,EAAe;AACf,cAAA,aAAA,GAAgB;AAAA,gBACZ,IAAI,aAAA,CAAc,EAAA;AAAA,gBAClB,IAAA,EAAM,cAAc,QAAA,EAAU,IAAA;AAAA,gBAC9B,SAAA,EAAW,cAAc,QAAA,EAAU;AAAA,eACvC;AAAA,YACJ;AAEA,YAAA,MAAM,UAAA,GAAa,MAAA,CAAO,aAAA,KAAkB,IAAA,IAAQ,OAAO,aAAA,KAAkB,KAAA,CAAA;AAE7E,YAAA,MAAM;AAAA,cACF,KAAA;AAAA,cACA,QAAA,EAAU,UAAA;AAAA,cACV,GAAI,aAAA,IAAiB,EAAE,aAAA,EAAc;AAAA,cACrC,GAAI,cAAc,EAAE,YAAA,EAAc,KAAK,eAAA,CAAgB,MAAA,CAAO,aAAa,CAAA;AAAE,aACjF;AAAA,UACJ;AAAA,QACJ;AAAA,MACJ;AAAA,IACJ,CAAA,SAAE;AACE,MAAA,MAAA,CAAO,WAAA,EAAY;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,eAAe,IAAA,EAAsB;AACjC,IAAA,OAAO,IAAA,CAAK,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AAAA,EACpC;AAAA,EAEA,YAAA,GAA0B;AACtB,IAAA,OAAO;AAAA,MACH,cAAA,EAAgB,IAAA;AAAA,MAChB,aAAA,EAAe,IAAA;AAAA,MACf,aAAA,EAAe;AAAA,KACnB;AAAA,EACJ;AAAA,EAEA,MAAM,WAAA,GAAgC;AAClC,IAAA,IAAI;AACA,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,cAAA,CAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,OAAA,CAAA,EAAW,EAAE,MAAA,EAAQ,KAAA,EAAO,CAAA;AAClF,MAAA,OAAO,IAAA,CAAK,EAAA;AAAA,IAChB,CAAA,CAAA,MAAQ;AACJ,MAAA,OAAO,KAAA;AAAA,IACX;AAAA,EACJ;AAAA,EAEA,MAAM,WAAW,OAAA,EAA+D;AAC5E,IAAA,MAAM,YAAA,GAAe,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA;AAC7C,IAAA,MAAM,KAAA,GAAQ,IAAI,UAAA,CAAW,YAAA,CAAa,MAAM,CAAA;AAChD,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,CAAa,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,KAAA,CAAM,CAAC,CAAA,GAAI,YAAA,CAAa,UAAA,CAAW,CAAC,CAAA;AAAA,IACxC;AACA,IAAA,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK,CAAC,KAAK,GAAG,EAAE,IAAA,EAAM,OAAA,CAAQ,QAAA,EAAU,CAAA;AACzD,IAAA,MAAM,QAAA,GAAW,IAAI,QAAA,EAAS;AAC9B,IAAA,QAAA,CAAS,MAAA,CAAO,MAAA,EAAQ,IAAA,EAAM,YAAY,CAAA;AAC1C,IAAA,QAAA,CAAS,MAAA,CAAO,OAAA,EAAS,OAAA,CAAQ,KAAA,IAAS,WAAW,CAAA;AACrD,IAAA,IAAI,QAAQ,QAAA,EAAU,QAAA,CAAS,MAAA,CAAO,UAAA,EAAY,QAAQ,QAAQ,CAAA;AAElE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,qBAAA,CAAA,EAAyB;AAAA,MAC/E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,QAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACL,cAAA,EAAgB;AAAA;AACpB,KACH,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO;AAAA,MACH,YAAY,IAAA,CAAK,IAAA;AAAA,MACjB,UAAA,EAAY,CAAA;AAAA;AAAA,MACZ,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,OAAA,CAAQ,QAAA,IAAY;AAAA,KACnD;AAAA,EACJ;AAAA,EAEA,OAAO,WAAW,OAAA,EAAsD;AACpE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,aAAA,CAAA,EAAiB;AAAA,MACvE,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,KAAA,EAAO,QAAQ,KAAA,IAAS,OAAA;AAAA,QACxB,OAAO,OAAA,CAAQ,IAAA;AAAA,QACf,KAAA,EAAO,QAAQ,OAAA,IAAW,OAAA;AAAA,QAC1B,eAAA,EAAiB,QAAQ,MAAA,IAAU;AAAA,OACtC;AAAA,KACJ,CAAA;AAED,IAAA,IAAI,CAAC,QAAA,CAAS,IAAA,QAAY,IAAI,kBAAA,CAAmB,4BAA4B,cAAc,CAAA;AAE3F,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,IAAA,CAAK,SAAA,EAAU;AACvC,IAAA,IAAI;AACA,MAAA,OAAO,IAAA,EAAM;AACT,QAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,QAAA,IAAI,IAAA,EAAM;AACV,QAAA,IAAI,KAAA,EAAO;AACP,UAAA,MAAM,SAAS,IAAI,WAAA,CAAY,QAAQ,CAAA,CAAE,OAAO,KAAK,CAAA;AACrD,UAAA,MAAM,EAAE,WAAA,EAAa,IAAA,CAAK,MAAM,CAAA,EAAE;AAAA,QACtC;AAAA,MACJ;AAAA,IACJ,CAAA,SAAE;AACE,MAAA,MAAA,CAAO,WAAA,EAAY;AAAA,IACvB;AAAA,EACJ;AAAA,EAEA,MAAM,cAAc,OAAA,EAAiD;AACjE,IAAA,MAAM,OAAA,GAAU;AAAA,MACZ,KAAA,EAAO,OAAA,CAAQ,KAAA,IAAS,IAAA,CAAK,YAAA;AAAA,MAC7B,QAAA,EAAU;AAAA,QACN;AAAA,UACI,IAAA,EAAM,MAAA;AAAA,UACN,OAAA,EAAS;AAAA,YACL,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,OAAA,CAAQ,UAAU,qBAAA,EAAsB;AAAA,YAC9D;AAAA,cACI,IAAA,EAAM,WAAA;AAAA,cACN,SAAA,EAAW;AAAA,gBACP,GAAA,EAAK,CAAA,uBAAA,EAA0B,OAAA,CAAQ,WAAW,CAAA;AAAA;AACtD;AACJ;AACJ;AACJ;AACJ,KACJ;AAEA,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,iBAAA,CAAA,EAAqB;AAAA,MAC3E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,OAAO;AAAA,KAC/B,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,OAAO;AAAA,MACH,WAAA,EAAa,IAAA,CAAK,OAAA,CAAQ,CAAC,EAAE,OAAA,CAAQ,OAAA;AAAA,MACrC,SAAS;AAAC;AAAA,KACd;AAAA,EACJ;AAAA,EAEA,MAAM,cAAc,OAAA,EAAqD;AACrE,IAAA,MAAM,WAAW,MAAM,IAAA,CAAK,eAAe,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,mBAAA,CAAA,EAAuB;AAAA,MAC7E,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,QACjB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,KAAA,EAAO,QAAQ,KAAA,IAAS,UAAA;AAAA,QACxB,CAAA,EAAG,CAAA;AAAA,QACH,IAAA,EAAM,QAAQ,UAAA,IAAc;AAAA,OAC/B;AAAA,KACJ,CAAA;AAED,IAAA,MAAM,IAAA,GAAO,MAAM,QAAA,CAAS,IAAA,EAAK;AACjC,IAAA,IAAI,MAAM,KAAA,EAAO;AACb,MAAA,MAAM,IAAI,kBAAA,CAAmB,IAAA,CAAK,KAAA,CAAM,OAAA,IAAW,2BAA2B,iBAAiB,CAAA;AAAA,IACnG;AACA,IAAA,MAAM,KAAA,GAAQ,IAAA,EAAM,IAAA,GAAO,CAAC,KAAK,EAAC;AAClC,IAAA,MAAM,QAAA,GACF,KAAA,CAAM,GAAA,KACL,KAAA,CAAM,QAAA,GAAW,CAAA,sBAAA,EAAyB,KAAA,CAAM,QAAQ,CAAA,CAAA,GAAK,IAAA,CAAA,KAC7D,KAAA,CAAM,SAAA,EAAW,GAAA,IAAO,IAAA,CAAA;AAC7B,IAAA,IAAI,CAAC,QAAA,EAAU;AACX,MAAA,MAAM,IAAI,kBAAA,CAAmB,0DAAA,EAA4D,iBAAiB,CAAA;AAAA,IAC9G;AACA,IAAA,OAAO;AAAA,MACH,QAAA;AAAA,MACA,eAAe,KAAA,CAAM;AAAA,KACzB;AAAA,EACJ;AACJ","file":"index.js","sourcesContent":["/**\n * Base class for all custom errors thrown by lemura.\n *\n * @example\n * throw new LemuraError('Something went wrong', 'UNKNOWN_ERROR');\n */\nexport class LemuraError extends Error {\n /**\n * @param message - The error message\n * @param code - The error code for programmatic handling\n * @param problem - A clear description of the problem for the end user\n * @param hints - A list of suggestions to resolve the issue\n */\n constructor(\n message: string,\n public readonly code: string,\n public readonly problem?: string,\n public readonly hints: string[] = []\n ) {\n super(message);\n this.name = 'LemuraError';\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n\n/** Error thrown when context exceeds max tokens and cannot be compressed further */\nexport class LemuraContextOverflowError extends LemuraError {\n constructor(message: string) {\n super(message, 'CONTEXT_OVERFLOW');\n this.name = 'LemuraContextOverflowError';\n }\n}\n\n/** Error thrown when a requested tool is not found in the registry */\nexport class LemuraToolNotFoundError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_NOT_FOUND');\n this.name = 'LemuraToolNotFoundError';\n }\n}\n\n/** Error thrown when an adapter encounters an API or formatting issue */\nexport class LemuraAdapterError extends LemuraError {\n constructor(\n message: string,\n code = 'ADAPTER_ERROR',\n public cause?: any,\n problem?: string,\n hints: string[] = []\n ) {\n super(message, code, problem, hints);\n this.name = 'LemuraAdapterError';\n }\n}\n\n/** Error thrown when a skill cannot be parsed or injected */\nexport class LemuraSkillInjectionError extends LemuraError {\n constructor(message: string) {\n super(message, 'SKILL_INJECTION_FAILED');\n this.name = 'LemuraSkillInjectionError';\n }\n}\n\n/** Error thrown when the ReAct loop exceeds the configured max iterations */\nexport class LemuraMaxIterationsError extends LemuraError {\n constructor(message: string) {\n super(message, 'MAX_ITERATIONS_EXCEEDED');\n this.name = 'LemuraMaxIterationsError';\n }\n}\n\n/** Error thrown when tool parameters fail JSON schema validation */\nexport class LemuraToolValidationError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_VALIDATION_FAILED');\n this.name = 'LemuraToolValidationError';\n }\n}\n\n/** Error thrown when a tool execute function exceeds its timeout */\nexport class LemuraToolTimeoutError extends LemuraError {\n constructor(message: string) {\n super(message, 'TOOL_TIMEOUT');\n this.name = 'LemuraToolTimeoutError';\n }\n}\n\n/** Base error thrown for any MCP server communication failure */\nexport class LemuraMCPError extends LemuraError {\n constructor(message: string, code = 'MCP_ERROR', problem?: string, hints: string[] = []) {\n super(message, code, problem, hints);\n this.name = 'LemuraMCPError';\n }\n}\n\n/** Error thrown when an MCP server cannot be connected to (spawn failure, network error, init failure) */\nexport class LemuraMCPConnectionError extends LemuraMCPError {\n constructor(message: string, problem?: string, hints: string[] = []) {\n super(message, 'MCP_CONNECTION_FAILED', problem, hints);\n this.name = 'LemuraMCPConnectionError';\n }\n}\n\n/** Error thrown when a call to an MCP server tool exceeds the configured timeout */\nexport class LemuraMCPTimeoutError extends LemuraMCPError {\n constructor(message: string) {\n super(message, 'MCP_TOOL_TIMEOUT');\n this.name = 'LemuraMCPTimeoutError';\n }\n}\n","import {\n IProviderAdapter,\n CompletionRequest,\n CompletionResponse,\n CompletionChunk,\n TranscriptionRequest,\n TranscriptionResponse,\n SynthesisRequest,\n AudioChunk,\n VisionRequest,\n VisionResponse,\n ImageGenRequest,\n ImageGenResponse,\n ModelInfo,\n LemuraAdapterError,\n} from '../types/index.js';\n\nexport interface RetryConfig {\n maxRetries: number;\n baseDelayMs: number;\n}\n\nexport interface OpenAICompatibleAdapterConfig {\n baseUrl?: string;\n apiKey?: string;\n defaultModel?: string;\n defaultHeaders?: Record<string, string>;\n timeout?: number;\n retry?: RetryConfig;\n}\n\n/**\n * Reference implementation of an OpenAI-compatible provider adapter.\n */\nexport class OpenAICompatibleAdapter implements IProviderAdapter {\n readonly name = 'openai_compatible';\n readonly version = '1.2.0';\n\n private baseUrl: string;\n private apiKey: string;\n private defaultModel: string;\n private defaultHeaders: Record<string, string>;\n private timeoutMs: number;\n private retryConfig: RetryConfig;\n\n constructor(config: OpenAICompatibleAdapterConfig = {}) {\n this.baseUrl = (\n config.baseUrl ??\n process.env.LEMURA_BASE_URL ??\n process.env.OPENAI_BASE_URL ??\n 'https://api.openai.com/v1'\n ).replace(/\\/$/, '');\n\n this.apiKey = config.apiKey ?? process.env.LEMURA_API_KEY ?? process.env.OPENAI_API_KEY ?? '';\n this.defaultModel = config.defaultModel ?? process.env.LEMURA_MODEL ?? process.env.OPENAI_MODEL ?? 'gpt-3.5-turbo';\n\n this.defaultHeaders = config.defaultHeaders || {};\n this.timeoutMs = config.timeout || 30000;\n this.retryConfig = config.retry || { maxRetries: 2, baseDelayMs: 1000 };\n }\n\n private async fetchWithRetry(url: string, init: RequestInit): Promise<Response> {\n let attempts = 0;\n while (attempts <= this.retryConfig.maxRetries) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeoutMs);\n\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n ...this.defaultHeaders,\n };\n\n if (init.headers) {\n Object.assign(headers, init.headers);\n }\n\n // Don't set Content-Type if it's 'unset' (for FormData)\n if (headers['Content-Type'] === 'unset') {\n delete headers['Content-Type'];\n } else if (!headers['Content-Type']) {\n headers['Content-Type'] = 'application/json';\n }\n\n const response = await fetch(url, {\n ...init,\n signal: controller.signal,\n headers,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) return response;\n\n // Retry on 429 and 503\n if ((response.status === 429 || response.status === 503) && attempts < this.retryConfig.maxRetries) {\n attempts++;\n const delay = this.retryConfig.baseDelayMs * Math.pow(2, attempts - 1);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n const errorText = await response.text().catch(() => '');\n let problem = 'The server replied with an error during the API call.';\n let hints = ['Check the API documentation for the provider you are using.'];\n\n if (response.status === 401) {\n problem = 'Authentication failed. The API key is invalid or missing.';\n hints = [\n 'Ensure your API key is correctly configured in the adapter or environment variables.',\n 'Check if the API key has expired or been revoked.'\n ];\n } else if (response.status === 404) {\n problem = 'The requested resource or model was not found.';\n hints = [\n 'Verify that the baseUrl is correct (e.g., https://api.openai.com/v1).',\n 'Check if the model name is correct and available for your account.',\n 'Ensure you are not appending extra paths to the baseUrl.'\n ];\n } else if (response.status === 429) {\n problem = 'Rate limit exceeded.';\n hints = [\n 'Wait a few seconds before retrying.',\n 'Check your usage limits and billing status on the provider dashboard.'\n ];\n }\n\n throw new LemuraAdapterError(\n `HTTP ${response.status}: ${errorText}`,\n 'HTTP_ERROR',\n { status: response.status, body: errorText },\n problem,\n hints\n );\n } catch (err) {\n if (err instanceof LemuraAdapterError) throw err;\n\n if (attempts < this.retryConfig.maxRetries) {\n attempts++;\n const delay = this.retryConfig.baseDelayMs * Math.pow(2, attempts - 1);\n await new Promise(resolve => setTimeout(resolve, delay));\n continue;\n }\n\n throw new LemuraAdapterError(\n `Network request failed: ${err instanceof Error ? err.message : String(err)}`,\n 'NETWORK_ERROR',\n err,\n 'A network error occurred while connecting to the provider.',\n [\n 'Check your internet connection.',\n 'Verify that the baseUrl is reachable from your network.',\n 'Check for proxy or firewall settings that might block the request.'\n ]\n );\n }\n }\n throw new LemuraAdapterError(\n 'Max retries exceeded',\n 'MAX_RETRIES',\n undefined,\n 'The request failed after multiple retry attempts.',\n ['Check if the provider service is down or experiencing high load.']\n );\n }\n\n private mapFinishReason(reason: string | null): CompletionResponse['finishReason'] {\n if (!reason) return 'stop';\n const r = reason.toLowerCase();\n if (r === 'tool_calls' || r === 'tool_call') return 'tool_call';\n if (r === 'length' || r === 'max_tokens') return 'max_tokens';\n if (r === 'content_filter' || r === 'error') return 'error';\n return 'stop';\n }\n\n private buildPayload(request: CompletionRequest): unknown {\n const payload: Record<string, unknown> = {\n model: request.model || this.defaultModel,\n messages: request.messages,\n };\n if (request.maxTokens !== undefined) payload.max_tokens = request.maxTokens;\n if (request.temperature !== undefined) payload.temperature = request.temperature;\n if (request.stopSequences?.length) payload.stop = request.stopSequences;\n if (request.stream) payload.stream = true;\n\n if (request.tools && request.tools.length > 0) {\n payload.tools = request.tools.map(t => ({\n type: 'function',\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters,\n }\n }));\n }\n\n return payload;\n }\n\n async complete(request: CompletionRequest): Promise<CompletionResponse> {\n const payload = this.buildPayload(request);\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n const data = await response.json();\n const choice = data.choices?.[0];\n if (!choice) {\n throw new LemuraAdapterError('Invalid response format: missing choices', 'INVALID_RESPONSE', data);\n }\n\n const message = choice.message;\n let toolCalls;\n\n if (message.tool_calls && message.tool_calls.length > 0) {\n toolCalls = message.tool_calls.map((tc: any) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n }));\n }\n\n return {\n content: message.content || '',\n toolCalls,\n finishReason: this.mapFinishReason(choice.finish_reason),\n usage: {\n promptTokens: data.usage?.prompt_tokens || 0,\n completionTokens: data.usage?.completion_tokens || 0,\n totalTokens: data.usage?.total_tokens || 0,\n },\n rawResponse: data\n };\n }\n\n async *stream(request: CompletionRequest): AsyncIterable<CompletionChunk> {\n const payload = this.buildPayload({ ...request, stream: true });\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n if (!response.body) {\n throw new LemuraAdapterError('Response body is null', 'STREAM_ERROR');\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder('utf-8');\n let buffer = '';\n\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() || '';\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed === 'data: [DONE]') continue;\n if (trimmed.startsWith('data: ')) {\n const jsonStr = trimmed.slice(6);\n let data;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n continue;\n }\n\n const choice = data.choices?.[0];\n if (!choice) continue;\n\n const delta = choice.delta?.content || '';\n const toolCallBlock = choice.delta?.tool_calls?.[0];\n let toolCallDelta;\n\n if (toolCallBlock) {\n toolCallDelta = {\n id: toolCallBlock.id,\n name: toolCallBlock.function?.name,\n arguments: toolCallBlock.function?.arguments,\n };\n }\n\n const isFinished = choice.finish_reason !== null && choice.finish_reason !== undefined;\n\n yield {\n delta,\n finished: isFinished,\n ...(toolCallDelta && { toolCallDelta }),\n ...(isFinished && { finishReason: this.mapFinishReason(choice.finish_reason) })\n };\n }\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n }\n\n getModelInfo(): ModelInfo {\n return {\n supportsVision: true,\n supportsTools: true,\n contextWindow: 128000\n };\n }\n\n async healthCheck(): Promise<boolean> {\n try {\n const resp = await this.fetchWithRetry(`${this.baseUrl}/models`, { method: 'GET' });\n return resp.ok;\n } catch {\n return false;\n }\n }\n\n async transcribe(request: TranscriptionRequest): Promise<TranscriptionResponse> {\n const binaryString = atob(request.audioBase64);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n const blob = new Blob([bytes], { type: request.mimeType });\n const formData = new FormData();\n formData.append('file', blob, 'audio.webm');\n formData.append('model', request.model || 'whisper-1');\n if (request.language) formData.append('language', request.language);\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/audio/transcriptions`, {\n method: 'POST',\n body: formData,\n headers: {\n 'Content-Type': 'unset'\n }\n });\n\n const data = await response.json();\n return {\n transcript: data.text,\n confidence: 1.0, // OpenAI doesn't return confidence in standard response\n language: data.language || request.language || 'en'\n };\n }\n\n async *synthesize(request: SynthesisRequest): AsyncIterable<AudioChunk> {\n const response = await this.fetchWithRetry(`${this.baseUrl}/audio/speech`, {\n method: 'POST',\n body: JSON.stringify({\n model: request.model || 'tts-1',\n input: request.text,\n voice: request.voiceId || 'alloy',\n response_format: request.format || 'mp3'\n })\n });\n\n if (!response.body) throw new LemuraAdapterError('No response body for TTS', 'STREAM_ERROR');\n\n const reader = response.body.getReader();\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n if (value) {\n const binary = new TextDecoder('latin1').decode(value);\n yield { audioBase64: btoa(binary) };\n }\n }\n } finally {\n reader.releaseLock();\n }\n }\n\n async describeImage(request: VisionRequest): Promise<VisionResponse> {\n const payload = {\n model: request.model || this.defaultModel,\n messages: [\n {\n role: 'user',\n content: [\n { type: 'text', text: request.prompt || 'Describe this image' },\n {\n type: 'image_url',\n image_url: {\n url: `data:image/jpeg;base64,${request.imageBase64}`\n }\n }\n ]\n }\n ]\n };\n\n const response = await this.fetchWithRetry(`${this.baseUrl}/chat/completions`, {\n method: 'POST',\n body: JSON.stringify(payload)\n });\n\n const data = await response.json();\n return {\n description: data.choices[0].message.content,\n objects: [] // OpenAI doesn't return structured objects in standard vision call\n };\n }\n\n async generateImage(request: ImageGenRequest): Promise<ImageGenResponse> {\n const response = await this.fetchWithRetry(`${this.baseUrl}/images/generations`, {\n method: 'POST',\n body: JSON.stringify({\n prompt: request.prompt,\n model: request.model || 'dall-e-3',\n n: 1,\n size: request.dimensions || '1024x1024'\n })\n });\n\n const data = await response.json();\n if (data?.error) {\n throw new LemuraAdapterError(data.error.message || 'Image generation failed', 'IMAGE_GEN_ERROR');\n }\n const first = data?.data?.[0] || {};\n const imageUrl =\n first.url ||\n (first.b64_json ? `data:image/png;base64,${first.b64_json}` : null) ||\n (first.image_url?.url || null);\n if (!imageUrl) {\n throw new LemuraAdapterError('Image generation returned no image URL or base64 payload', 'IMAGE_GEN_EMPTY');\n }\n return {\n imageUrl,\n revisedPrompt: first.revised_prompt\n };\n }\n}\n"]}
|
package/dist/adapters/index.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var LemuraAdapterError = class extends LemuraError {
|
|
|
26
26
|
// src/adapters/OpenAICompatibleAdapter.ts
|
|
27
27
|
var OpenAICompatibleAdapter = class {
|
|
28
28
|
name = "openai_compatible";
|
|
29
|
-
version = "1.
|
|
29
|
+
version = "1.2.0";
|
|
30
30
|
baseUrl;
|
|
31
31
|
apiKey;
|
|
32
32
|
defaultModel;
|
|
@@ -275,7 +275,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
275
275
|
const blob = new Blob([bytes], { type: request.mimeType });
|
|
276
276
|
const formData = new FormData();
|
|
277
277
|
formData.append("file", blob, "audio.webm");
|
|
278
|
-
formData.append("model", "whisper-1");
|
|
278
|
+
formData.append("model", request.model || "whisper-1");
|
|
279
279
|
if (request.language) formData.append("language", request.language);
|
|
280
280
|
const response = await this.fetchWithRetry(`${this.baseUrl}/audio/transcriptions`, {
|
|
281
281
|
method: "POST",
|
|
@@ -296,7 +296,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
296
296
|
const response = await this.fetchWithRetry(`${this.baseUrl}/audio/speech`, {
|
|
297
297
|
method: "POST",
|
|
298
298
|
body: JSON.stringify({
|
|
299
|
-
model: "tts-1",
|
|
299
|
+
model: request.model || "tts-1",
|
|
300
300
|
input: request.text,
|
|
301
301
|
voice: request.voiceId || "alloy",
|
|
302
302
|
response_format: request.format || "mp3"
|
|
@@ -319,7 +319,7 @@ var OpenAICompatibleAdapter = class {
|
|
|
319
319
|
}
|
|
320
320
|
async describeImage(request) {
|
|
321
321
|
const payload = {
|
|
322
|
-
model: this.defaultModel,
|
|
322
|
+
model: request.model || this.defaultModel,
|
|
323
323
|
messages: [
|
|
324
324
|
{
|
|
325
325
|
role: "user",
|
|
@@ -351,15 +351,23 @@ var OpenAICompatibleAdapter = class {
|
|
|
351
351
|
method: "POST",
|
|
352
352
|
body: JSON.stringify({
|
|
353
353
|
prompt: request.prompt,
|
|
354
|
-
model: "dall-e-3",
|
|
354
|
+
model: request.model || "dall-e-3",
|
|
355
355
|
n: 1,
|
|
356
356
|
size: request.dimensions || "1024x1024"
|
|
357
357
|
})
|
|
358
358
|
});
|
|
359
359
|
const data = await response.json();
|
|
360
|
+
if (data?.error) {
|
|
361
|
+
throw new LemuraAdapterError(data.error.message || "Image generation failed", "IMAGE_GEN_ERROR");
|
|
362
|
+
}
|
|
363
|
+
const first = data?.data?.[0] || {};
|
|
364
|
+
const imageUrl = first.url || (first.b64_json ? `data:image/png;base64,${first.b64_json}` : null) || (first.image_url?.url || null);
|
|
365
|
+
if (!imageUrl) {
|
|
366
|
+
throw new LemuraAdapterError("Image generation returned no image URL or base64 payload", "IMAGE_GEN_EMPTY");
|
|
367
|
+
}
|
|
360
368
|
return {
|
|
361
|
-
imageUrl
|
|
362
|
-
revisedPrompt:
|
|
369
|
+
imageUrl,
|
|
370
|
+
revisedPrompt: first.revised_prompt
|
|
363
371
|
};
|
|
364
372
|
}
|
|
365
373
|
};
|