adonis-ai-kit 0.0.0-stage → 1.1.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.
Files changed (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +325 -2
  3. package/dist/commands/ai_test.d.ts +12 -0
  4. package/dist/commands/ai_test.d.ts.map +1 -0
  5. package/dist/commands/ai_test.js +98 -0
  6. package/dist/commands/ai_test.js.map +1 -0
  7. package/dist/commands/main.d.ts +14 -0
  8. package/dist/commands/main.d.ts.map +1 -0
  9. package/dist/commands/main.js +31 -0
  10. package/dist/commands/main.js.map +1 -0
  11. package/dist/commands/make_agent.d.ts +13 -0
  12. package/dist/commands/make_agent.d.ts.map +1 -0
  13. package/dist/commands/make_agent.js +116 -0
  14. package/dist/commands/make_agent.js.map +1 -0
  15. package/dist/providers/ai_provider.d.ts +23 -0
  16. package/dist/providers/ai_provider.d.ts.map +1 -0
  17. package/dist/providers/ai_provider.js +34 -0
  18. package/dist/providers/ai_provider.js.map +1 -0
  19. package/dist/services/main.d.ts +4 -0
  20. package/dist/services/main.d.ts.map +1 -0
  21. package/dist/services/main.js +7 -0
  22. package/dist/services/main.js.map +1 -0
  23. package/dist/src/acp/acp_agents.d.ts +75 -0
  24. package/dist/src/acp/acp_agents.d.ts.map +1 -0
  25. package/dist/src/acp/acp_agents.js +343 -0
  26. package/dist/src/acp/acp_agents.js.map +1 -0
  27. package/dist/src/acp/index.d.ts +4 -0
  28. package/dist/src/acp/index.d.ts.map +1 -0
  29. package/dist/src/acp/index.js +4 -0
  30. package/dist/src/acp/index.js.map +1 -0
  31. package/dist/src/acp/provider.d.ts +64 -0
  32. package/dist/src/acp/provider.d.ts.map +1 -0
  33. package/dist/src/acp/provider.js +255 -0
  34. package/dist/src/acp/provider.js.map +1 -0
  35. package/dist/src/acp/types.d.ts +107 -0
  36. package/dist/src/acp/types.d.ts.map +1 -0
  37. package/dist/src/acp/types.js +2 -0
  38. package/dist/src/acp/types.js.map +1 -0
  39. package/dist/src/agents/agent_runner.d.ts +60 -0
  40. package/dist/src/agents/agent_runner.d.ts.map +1 -0
  41. package/dist/src/agents/agent_runner.js +134 -0
  42. package/dist/src/agents/agent_runner.js.map +1 -0
  43. package/dist/src/agents/index.d.ts +4 -0
  44. package/dist/src/agents/index.d.ts.map +1 -0
  45. package/dist/src/agents/index.js +4 -0
  46. package/dist/src/agents/index.js.map +1 -0
  47. package/dist/src/agents/loader.d.ts +56 -0
  48. package/dist/src/agents/loader.d.ts.map +1 -0
  49. package/dist/src/agents/loader.js +184 -0
  50. package/dist/src/agents/loader.js.map +1 -0
  51. package/dist/src/agents/manifest.d.ts +61 -0
  52. package/dist/src/agents/manifest.d.ts.map +1 -0
  53. package/dist/src/agents/manifest.js +35 -0
  54. package/dist/src/agents/manifest.js.map +1 -0
  55. package/dist/src/ai_manager.d.ts +136 -0
  56. package/dist/src/ai_manager.d.ts.map +1 -0
  57. package/dist/src/ai_manager.js +701 -0
  58. package/dist/src/ai_manager.js.map +1 -0
  59. package/dist/src/budget/budget_allocator.d.ts +37 -0
  60. package/dist/src/budget/budget_allocator.d.ts.map +1 -0
  61. package/dist/src/budget/budget_allocator.js +98 -0
  62. package/dist/src/budget/budget_allocator.js.map +1 -0
  63. package/dist/src/budget/budget_enforcer.d.ts +70 -0
  64. package/dist/src/budget/budget_enforcer.d.ts.map +1 -0
  65. package/dist/src/budget/budget_enforcer.js +195 -0
  66. package/dist/src/budget/budget_enforcer.js.map +1 -0
  67. package/dist/src/budget/cost_tracker.d.ts +71 -0
  68. package/dist/src/budget/cost_tracker.d.ts.map +1 -0
  69. package/dist/src/budget/cost_tracker.js +199 -0
  70. package/dist/src/budget/cost_tracker.js.map +1 -0
  71. package/dist/src/budget/index.d.ts +6 -0
  72. package/dist/src/budget/index.d.ts.map +1 -0
  73. package/dist/src/budget/index.js +6 -0
  74. package/dist/src/budget/index.js.map +1 -0
  75. package/dist/src/budget/pricing.d.ts +35 -0
  76. package/dist/src/budget/pricing.d.ts.map +1 -0
  77. package/dist/src/budget/pricing.js +129 -0
  78. package/dist/src/budget/pricing.js.map +1 -0
  79. package/dist/src/budget/types.d.ts +91 -0
  80. package/dist/src/budget/types.d.ts.map +1 -0
  81. package/dist/src/budget/types.js +2 -0
  82. package/dist/src/budget/types.js.map +1 -0
  83. package/dist/src/catalog/index.d.ts +3 -0
  84. package/dist/src/catalog/index.d.ts.map +1 -0
  85. package/dist/src/catalog/index.js +3 -0
  86. package/dist/src/catalog/index.js.map +1 -0
  87. package/dist/src/catalog/models_dev.d.ts +87 -0
  88. package/dist/src/catalog/models_dev.d.ts.map +1 -0
  89. package/dist/src/catalog/models_dev.js +38 -0
  90. package/dist/src/catalog/models_dev.js.map +1 -0
  91. package/dist/src/catalog/source.d.ts +52 -0
  92. package/dist/src/catalog/source.d.ts.map +1 -0
  93. package/dist/src/catalog/source.js +668 -0
  94. package/dist/src/catalog/source.js.map +1 -0
  95. package/dist/src/circuit_breaker.d.ts +40 -0
  96. package/dist/src/circuit_breaker.d.ts.map +1 -0
  97. package/dist/src/circuit_breaker.js +172 -0
  98. package/dist/src/circuit_breaker.js.map +1 -0
  99. package/dist/src/define_config.d.ts +11 -0
  100. package/dist/src/define_config.d.ts.map +1 -0
  101. package/dist/src/define_config.js +48 -0
  102. package/dist/src/define_config.js.map +1 -0
  103. package/dist/src/error_classifier.d.ts +17 -0
  104. package/dist/src/error_classifier.d.ts.map +1 -0
  105. package/dist/src/error_classifier.js +80 -0
  106. package/dist/src/error_classifier.js.map +1 -0
  107. package/dist/src/errors.d.ts +52 -0
  108. package/dist/src/errors.d.ts.map +1 -0
  109. package/dist/src/errors.js +70 -0
  110. package/dist/src/errors.js.map +1 -0
  111. package/dist/src/guard/confirmation.d.ts +67 -0
  112. package/dist/src/guard/confirmation.d.ts.map +1 -0
  113. package/dist/src/guard/confirmation.js +180 -0
  114. package/dist/src/guard/confirmation.js.map +1 -0
  115. package/dist/src/guard/errors.d.ts +10 -0
  116. package/dist/src/guard/errors.d.ts.map +1 -0
  117. package/dist/src/guard/errors.js +14 -0
  118. package/dist/src/guard/errors.js.map +1 -0
  119. package/dist/src/guard/guard.d.ts +47 -0
  120. package/dist/src/guard/guard.d.ts.map +1 -0
  121. package/dist/src/guard/guard.js +133 -0
  122. package/dist/src/guard/guard.js.map +1 -0
  123. package/dist/src/guard/index.d.ts +7 -0
  124. package/dist/src/guard/index.d.ts.map +1 -0
  125. package/dist/src/guard/index.js +7 -0
  126. package/dist/src/guard/index.js.map +1 -0
  127. package/dist/src/guard/registry.d.ts +66 -0
  128. package/dist/src/guard/registry.d.ts.map +1 -0
  129. package/dist/src/guard/registry.js +182 -0
  130. package/dist/src/guard/registry.js.map +1 -0
  131. package/dist/src/guard/schema_registry.d.ts +37 -0
  132. package/dist/src/guard/schema_registry.d.ts.map +1 -0
  133. package/dist/src/guard/schema_registry.js +57 -0
  134. package/dist/src/guard/schema_registry.js.map +1 -0
  135. package/dist/src/guard/types.d.ts +64 -0
  136. package/dist/src/guard/types.d.ts.map +1 -0
  137. package/dist/src/guard/types.js +2 -0
  138. package/dist/src/guard/types.js.map +1 -0
  139. package/dist/src/index.d.ts +13 -0
  140. package/dist/src/index.d.ts.map +1 -0
  141. package/dist/src/index.js +12 -0
  142. package/dist/src/index.js.map +1 -0
  143. package/dist/src/response_macro.d.ts +16 -0
  144. package/dist/src/response_macro.d.ts.map +1 -0
  145. package/dist/src/response_macro.js +151 -0
  146. package/dist/src/response_macro.js.map +1 -0
  147. package/dist/src/types.d.ts +297 -0
  148. package/dist/src/types.d.ts.map +1 -0
  149. package/dist/src/types.js +2 -0
  150. package/dist/src/types.js.map +1 -0
  151. package/dist/src/usage.d.ts +13 -0
  152. package/dist/src/usage.d.ts.map +1 -0
  153. package/dist/src/usage.js +61 -0
  154. package/dist/src/usage.js.map +1 -0
  155. package/package.json +141 -3
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 IvanGlazyrin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,326 @@
1
- # Temporary Holding Version
1
+ # adonis-ai
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ > **Production-grade AI & Agentic workflow toolkit for AdonisJS 7**, powered by Vercel AI SDK v7, multi-provider cascading fallback, circuit breakers, tool security guardrails, token budget tracking, models.dev live catalog, and ACP (Agent Client Protocol) coding agents.
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+ [![npm](https://img.shields.io/npm/v/adonis-ai-kit.svg)](https://www.npmjs.com/package/adonis-ai-kit)
7
+ [![AdonisJS](https://img.shields.io/badge/AdonisJS-7.x-5A45FF.svg)](https://adonisjs.com)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-ES2022%20%2F%20NodeNext-blue.svg)](https://www.typescriptlang.org)
9
+ [![Vercel AI SDK](https://img.shields.io/badge/Vercel%20AI%20SDK-v7.x-black.svg)](https://sdk.vercel.ai)
10
+ [![Node](https://img.shields.io/badge/node-%3E%3D22.0.0-brightgreen.svg)](https://nodejs.org)
11
+
12
+ ---
13
+
14
+ ## Highlights & Architectural Comparison
15
+
16
+ While frameworks like **Laravel AI** and **Prism** bring basic prompt-level abstractions to PHP, enterprise production systems require strict SRE resilience, tool execution guardrails, cost guarantees, and streaming protocol integrity. **`adonis-ai`** is built from the ground up for high-concurrency Node.js microservices:
17
+
18
+ | Feature | `adonis-ai` (AdonisJS 7) | Laravel AI / Prism (PHP) |
19
+ | :--- | :--- | :--- |
20
+ | **Foundation Engine** | **Vercel AI SDK v7** (native Node.js async streams & tool calls) | Custom cURL/Guzzle wrappers |
21
+ | **Circuit Breaker** | **Per `provider:model` key** (isolated half-open state, probe limits) | Global or none |
22
+ | **Cascading Fallbacks** | **Safe**: never replays side-effects if tool calls already started | Retries from scratch (risk of double actions) |
23
+ | **Tool Security (Guardrails)** | **Fail-closed** with Human-in-the-Loop (HITL), concurrent slots | Basic parameter mapping |
24
+ | **Token Budget & Cost** | **Live USD pricing**, ring-buffer memory, cache-read & reasoning tokens | Raw token count or static tables |
25
+ | **Catalog Auto-Discovery** | **models.dev integration** with TTL cache & atomic writes | Static configuration files |
26
+ | **Agent Protocols** | **ACP (Agent Client Protocol)** for Claude Code, opencode & subagents | Basic prompt templates |
27
+ | **HTTP Streaming** | **`response.streamAI()` macro** with heartbeats, SSE frames & client-abort hook | PHP chunked response buffers |
28
+
29
+ ---
30
+
31
+ ## Architecture Overview
32
+
33
+ ```mermaid
34
+ flowchart TD
35
+ UserApp["AdonisJS Controller / Service"] --> AiManager["AiManager (Singleton Service)"]
36
+
37
+ subgraph SRE_Resilience ["SRE Resilience & Fallback Layer"]
38
+ AiManager --> CircuitBreaker["Circuit Breaker (provider:model)"]
39
+ CircuitBreaker --> FallbackCascade["Cascading Provider Fallback"]
40
+ end
41
+
42
+ subgraph Execution_Layer ["Execution & Agent Layer"]
43
+ FallbackCascade --> Providers["LLM Drivers (OpenAI, Anthropic, Google, Groq, ACP)"]
44
+ FallbackCascade --> AgentRunner["AgentRunner (Manifest + Skills)"]
45
+ AgentRunner --> ToolRegistry["Tool Registry (PolicyGuard)"]
46
+ ToolRegistry --> HITL["ConfirmationService (Human-in-the-Loop)"]
47
+ end
48
+
49
+ subgraph Observability_Cost ["Observability & Governance"]
50
+ Providers --> CostTracker["CostTracker (Ring Buffer)"]
51
+ Providers --> BudgetEnforcer["BudgetEnforcer (Atomic Reservations)"]
52
+ AiManager -.-> ModelsDev["models.dev Catalog (Live Pricing & Limits)"]
53
+ end
54
+
55
+ subgraph Transport_Layer ["Transport Layer"]
56
+ AiManager --> SSE["response.streamAI() Macro (SSE / Heartbeats / Abort)"]
57
+ end
58
+ ```
59
+
60
+ ---
61
+
62
+ ## Installation
63
+
64
+ ```bash
65
+ npm install adonis-ai-kit
66
+ # or
67
+ pnpm add adonis-ai-kit
68
+ ```
69
+
70
+ > Package name on npm is `adonis-ai-kit` (the `adonis-ai` name on npm is taken by another project).
71
+ > The source repository is [github.com/IvanGlazyrin/adonis-ai-kit](https://github.com/IvanGlazyrin/adonis-ai-kit).
72
+
73
+ Add the provider to `adonisrc.ts`:
74
+
75
+ ```ts
76
+ export default defineConfig({
77
+ providers: [
78
+ // ...
79
+ () => import('adonis-ai-kit/providers/ai_provider')
80
+ ]
81
+ })
82
+ ```
83
+
84
+ Configure your providers in `config/ai.ts`:
85
+
86
+ ```ts
87
+ import env from '#start/env'
88
+ import { defineConfig } from 'adonis-ai-kit'
89
+
90
+ export default defineConfig({
91
+ default: 'openai',
92
+ providers: {
93
+ openai: {
94
+ driver: 'openai',
95
+ apiKey: env.get('OPENAI_API_KEY'),
96
+ defaultModel: 'gpt-4o',
97
+ },
98
+ anthropic: {
99
+ driver: 'anthropic',
100
+ apiKey: env.get('ANTHROPIC_API_KEY'),
101
+ defaultModel: 'claude-3-7-sonnet-20250219',
102
+ },
103
+ },
104
+ // Automatically fallback to Anthropic if OpenAI is throttled (429) or down (5xx)
105
+ fallbackCascade: ['anthropic'],
106
+ circuitBreaker: {
107
+ failureThreshold: 5,
108
+ recoveryTimeoutMs: 30_000,
109
+ halfOpenMaxAttempts: 2,
110
+ },
111
+ })
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Core Capabilities
117
+
118
+ ### 1. Basic Generation & Multi-Provider Fallback
119
+
120
+ Generate text with automatic token usage tracking and USD calculation:
121
+
122
+ ```ts
123
+ import ai from 'adonis-ai-kit/services/main'
124
+
125
+ const result = await ai.generateText({
126
+ prompt: 'Explain vector indexing in 3 sentences',
127
+ })
128
+
129
+ console.log(result.text)
130
+ console.log(`Duration: ${result.durationMs}ms, Cost: $${result.costUsd}`)
131
+ console.log(`Tokens: in=${result.usage.inputTokens}, out=${result.usage.outputTokens}, cached=${result.usage.cacheReadTokens}`)
132
+ ```
133
+
134
+ If OpenAI returns `429 Rate Limit` or `503 Service Unavailable`, `adonis-ai` automatically routes the request to `anthropic` with its configured model, recording circuit breaker metrics.
135
+
136
+ ---
137
+
138
+ ### 2. Structured Output with Zod Schema
139
+
140
+ ```ts
141
+ import { z } from 'zod'
142
+ import ai from 'adonis-ai-kit/services/main'
143
+
144
+ const resumeSchema = z.object({
145
+ fullName: z.string(),
146
+ skills: z.array(z.string()),
147
+ yearsOfExperience: z.number(),
148
+ })
149
+
150
+ const { object } = await ai.generateObject({
151
+ prompt: 'Extract candidate details: Ivan Glazyrin, 9 years in TS and Go',
152
+ schema: resumeSchema,
153
+ })
154
+
155
+ console.log(object.skills) // ['TypeScript', 'Go', ...]
156
+ ```
157
+
158
+ ---
159
+
160
+ ### 3. Server-Sent Events (SSE) Streaming in AdonisJS Controllers
161
+
162
+ Use the built-in `response.streamAI()` macro:
163
+
164
+ ```ts
165
+ import type { HttpContext } from '@adonisjs/core/http'
166
+ import ai from 'adonis-ai-kit/services/main'
167
+
168
+ export default class ChatController {
169
+ async stream({ request, response }: HttpContext) {
170
+ const stream = await ai.streamText({
171
+ prompt: request.input('message'),
172
+ model: 'gpt-4o',
173
+ })
174
+
175
+ // Sets 'Content-Type: text/event-stream', sends heartbeat pings,
176
+ // and automatically calls stream.abort() if the client disconnects!
177
+ return response.streamAI(stream, {
178
+ heartbeatMs: 15_000,
179
+ mode: 'sse',
180
+ })
181
+ }
182
+ }
183
+ ```
184
+
185
+ ---
186
+
187
+ ### 4. Tool Security Guardrails & Human-in-the-Loop (HITL)
188
+
189
+ Prevent untrusted AI models from executing destructive operations:
190
+
191
+ ```ts
192
+ import { ToolRegistry, ConfirmationService, PolicyGuard } from 'adonis-ai-kit/guard'
193
+ import { tool } from 'ai'
194
+ import { z } from 'zod'
195
+
196
+ const confirmationService = new ConfirmationService({ timeoutMs: 60_000 })
197
+ const registry = new ToolRegistry(confirmationService)
198
+
199
+ // Define tools
200
+ registry.register(
201
+ 'deploy_service',
202
+ tool({
203
+ description: 'Deploy service to cluster',
204
+ parameters: z.object({ cluster: z.string(), service: z.string() }),
205
+ execute: async ({ cluster, service }) => `Deployed ${service} to ${cluster}`,
206
+ }),
207
+ { permission: 'ask', maxCallsPerSession: 1 } // Requires human confirmation!
208
+ )
209
+
210
+ // When the model calls 'deploy_service', confirmationService pauses execution,
211
+ // emits a confirmation request event, and resumes only when approved!
212
+ ```
213
+
214
+ ---
215
+
216
+ ### 5. Cost Tracking & Atomic Token Budget Enforcement
217
+
218
+ ```ts
219
+ import { CostTracker, BudgetEnforcer } from 'adonis-ai-kit/budget'
220
+
221
+ const tracker = new CostTracker({ maxRecords: 10_000 })
222
+ const enforcer = new BudgetEnforcer({
223
+ maxCostUsd: 100.0,
224
+ maxInputTokens: 5_000_000,
225
+ maxOutputTokens: 1_000_000,
226
+ })
227
+
228
+ // Atomic pre-flight reservation prevents concurrent race conditions
229
+ const reservation = enforcer.reserve('user-session-42', { estimatedCostUsd: 0.05 })
230
+ if (!reservation.allowed) {
231
+ throw new Error('Budget exceeded')
232
+ }
233
+
234
+ try {
235
+ // run LLM request...
236
+ enforcer.settle(reservation.reservationId, { costUsd: 0.038 })
237
+ } catch (e) {
238
+ enforcer.release(reservation.reservationId)
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ### 6. ACP (Agent Client Protocol) Coding Agents
245
+
246
+ Run subagents using local CLI tools like **Claude Code**, **opencode**, or custom ACP binaries with sanitized environments:
247
+
248
+ ```ts
249
+ import { AgentRunner, AgentLoader } from 'adonis-ai-kit/agents'
250
+
251
+ const loader = new AgentLoader({
252
+ configsDir: './resources/agent-configs',
253
+ skillsDir: './resources/agent-skills',
254
+ })
255
+
256
+ const runner = new AgentRunner(aiManager, registry, loader)
257
+ const execution = await runner.run({
258
+ agentId: 'code-reviewer',
259
+ userPrompt: 'Audit packages/adonis-ai for race conditions',
260
+ })
261
+ ```
262
+
263
+ ---
264
+
265
+ ## Ace CLI Commands
266
+
267
+ `adonis-ai` registers helpful Ace commands:
268
+
269
+ ```bash
270
+ # Test connectivity, latency, and model availability across configured providers
271
+ node ace ai:test
272
+
273
+ # Scaffold a new production agent prompt and schema
274
+ node ace make:ai-agent backend-architect --mode=primary
275
+ ```
276
+
277
+ ---
278
+
279
+ ## Testing & Quality
280
+
281
+ The package includes a comprehensive regression test suite with 100% pass rate:
282
+
283
+ ```bash
284
+ npm run test:regression
285
+ ```
286
+
287
+ - **Token Budget**: Rate calculations, cache-read discounts, reasoning token surcharges, ring-buffer bounded memory.
288
+ - **Tool Guard**: Policy enforcement (`allow`, `ask`, `deny`), concurrency slots, fail-closed handlers, session validation.
289
+ - **Adonis AI Core**: Cascading failovers without duplicate side-effects, SSE keepalive frames, models.dev live discovery & TTL, ACP command sanitization.
290
+
291
+ ---
292
+
293
+ ## Development & Release
294
+
295
+ ```bash
296
+ git clone https://github.com/IvanGlazyrin/adonis-ai-kit.git
297
+ cd adonis-ai-kit
298
+ npm install
299
+ npm run build
300
+ npm run test:regression
301
+ ```
302
+
303
+ Consume the local build from an AdonisJS app without publishing:
304
+
305
+ ```bash
306
+ # in the app
307
+ npm install ../path/to/adonis-ai-kit # file: dependency
308
+ # or globally
309
+ cd ../adonis-ai-kit && npm link
310
+ cd ../my-app && npm link adonis-ai-kit
311
+ ```
312
+
313
+ Releases are published to npm by pushing a version tag:
314
+
315
+ ```bash
316
+ npm version patch # bumps package.json + tag v1.1.1
317
+ git push --follow-tags # .github/workflows/release.yml runs npm publish
318
+ ```
319
+
320
+ The workflow requires an `NPM_TOKEN` secret in the repository settings.
321
+
322
+ ---
323
+
324
+ ## License
325
+
326
+ MIT © [Ivan Glazyrin](https://github.com/IvanGlazyrin) (glazrus97@gmail.com)
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '@adonisjs/core/ace';
2
+ import type { CommandOptions } from '@adonisjs/core/types/ace';
3
+ export default class AiTestCommand extends BaseCommand {
4
+ static commandName: string;
5
+ static description: string;
6
+ static options: CommandOptions;
7
+ provider?: string;
8
+ model?: string;
9
+ testPrompt: string;
10
+ run(): Promise<void>;
11
+ }
12
+ //# sourceMappingURL=ai_test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai_test.d.ts","sourceRoot":"","sources":["../../commands/ai_test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAS,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAE9D,MAAM,CAAC,OAAO,OAAO,aAAc,SAAQ,WAAW;IACpD,MAAM,CAAC,WAAW,SAAY;IAC9B,MAAM,CAAC,WAAW,SAA4E;IAE9F,MAAM,CAAC,OAAO,EAAE,cAAc,CAE7B;IAGO,QAAQ,CAAC,EAAE,MAAM,CAAA;IAGjB,KAAK,CAAC,EAAE,MAAM,CAAA;IAOd,UAAU,EAAE,MAAM,CAAA;IAEpB,GAAG;CA4EV"}
@@ -0,0 +1,98 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { BaseCommand, flags } from '@adonisjs/core/ace';
11
+ export default class AiTestCommand extends BaseCommand {
12
+ static commandName = 'ai:test';
13
+ static description = 'Test connectivity, latency, and generation with configured AI providers';
14
+ static options = {
15
+ startApp: true,
16
+ };
17
+ async run() {
18
+ const ai = await this.app.container.make('ai');
19
+ this.ui.logger.info('🤖 Testing Adonis AI Provider Connectivity...\n');
20
+ const config = ai.getConfig();
21
+ const providersToTest = this.provider ? [this.provider] : Object.keys(config.providers);
22
+ if (providersToTest.length === 0) {
23
+ this.ui.logger.error('No AI providers configured in config/ai.ts!');
24
+ return;
25
+ }
26
+ const table = this.ui.table();
27
+ table.head(['Provider', 'Model', 'Status', 'Latency', 'Circuit Breaker', 'Cost ($)']);
28
+ for (const pName of providersToTest) {
29
+ const pConfig = config.providers[pName];
30
+ if (!pConfig) {
31
+ this.ui.logger.error(`Provider "${pName}" not found in config!`);
32
+ continue;
33
+ }
34
+ const testModel = this.model ?? pConfig.defaultModel ?? 'default';
35
+ const start = Date.now();
36
+ try {
37
+ const response = await ai.generateText({
38
+ provider: pName,
39
+ model: this.model,
40
+ prompt: this.testPrompt || "Respond with PONG and your model identity in 10 words or less.",
41
+ maxOutputTokens: 50,
42
+ agentName: 'ace-ai-test',
43
+ });
44
+ const latency = Date.now() - start;
45
+ const stats = ai.getCircuitBreaker().getStats(`${response.provider}:${response.model}`);
46
+ // A fallback provider answering is NOT a pass for the provider under test
47
+ const answeredByFallback = response.provider !== pName;
48
+ table.row([
49
+ this.colors.cyan(pName),
50
+ response.model,
51
+ answeredByFallback
52
+ ? this.colors.yellow(`⚠ FALLBACK (${response.provider})`)
53
+ : this.colors.green('✔ OK'),
54
+ `${latency}ms`,
55
+ this.colors.green(stats.state.toUpperCase()),
56
+ response.costUsd !== undefined ? `$${response.costUsd.toFixed(6)}` : 'N/A',
57
+ ]);
58
+ this.ui.logger.info(`[${pName}] Output: "${response.text.trim()}"`);
59
+ }
60
+ catch (err) {
61
+ const latency = Date.now() - start;
62
+ const stats = ai.getCircuitBreaker().getStats(`${pName}:${testModel}`);
63
+ table.row([
64
+ this.colors.cyan(pName),
65
+ testModel,
66
+ this.colors.red('✖ FAILED'),
67
+ `${latency}ms`,
68
+ this.colors.red(stats.state.toUpperCase()),
69
+ 'N/A',
70
+ ]);
71
+ this.ui.logger.error(`[${pName}] Error: ${err.message}`);
72
+ }
73
+ }
74
+ this.ui.logger.log('');
75
+ table.render();
76
+ this.ui.logger.log('');
77
+ const totalCost = ai.getCostTracker().getTotalCost();
78
+ const totalTokens = ai.getCostTracker().getTotalTokens();
79
+ this.ui.logger.info(`Total session cost: ${totalCost.toFixed(6)} | Tokens: ${totalTokens}`);
80
+ }
81
+ }
82
+ __decorate([
83
+ flags.string({ description: 'Specific provider to test (e.g. openai, anthropic, gemini, groq, ollama)' }),
84
+ __metadata("design:type", String)
85
+ ], AiTestCommand.prototype, "provider", void 0);
86
+ __decorate([
87
+ flags.string({ description: 'Model to test with' }),
88
+ __metadata("design:type", String)
89
+ ], AiTestCommand.prototype, "model", void 0);
90
+ __decorate([
91
+ flags.string({
92
+ name: 'prompt',
93
+ description: 'Test prompt to send',
94
+ default: 'Respond with "PONG" and your model identity in 10 words or less.',
95
+ }),
96
+ __metadata("design:type", String)
97
+ ], AiTestCommand.prototype, "testPrompt", void 0);
98
+ //# sourceMappingURL=ai_test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai_test.js","sourceRoot":"","sources":["../../commands/ai_test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { CommandMetaData } from '@adonisjs/core/types/ace';
2
+ import type { BaseCommand } from '@adonisjs/core/ace';
3
+ type CommandClass = typeof BaseCommand;
4
+ /**
5
+ * Ace command loader contract: returns metadata of every command in this package.
6
+ * Metadata is derived from the command classes themselves, so no generated `commands.json` is needed.
7
+ */
8
+ export declare function getMetaData(): Promise<CommandMetaData[]>;
9
+ /**
10
+ * Ace command loader contract: resolves the command class for the given metadata.
11
+ */
12
+ export declare function getCommand(metaData: Pick<CommandMetaData, 'commandName'>): Promise<CommandClass | null>;
13
+ export {};
14
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../commands/main.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAErD,KAAK,YAAY,GAAG,OAAO,WAAW,CAAA;AActC;;;GAGG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAM9D;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,CAAC,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAG7G"}
@@ -0,0 +1,31 @@
1
+ const loaders = [
2
+ () => import('./ai_test.js'),
3
+ () => import('./make_agent.js'),
4
+ ];
5
+ let cachedMetaData;
6
+ const cachedCommands = new Map();
7
+ async function loadAll() {
8
+ return Promise.all(loaders.map(async (load) => (await load()).default));
9
+ }
10
+ /**
11
+ * Ace command loader contract: returns metadata of every command in this package.
12
+ * Metadata is derived from the command classes themselves, so no generated `commands.json` is needed.
13
+ */
14
+ export async function getMetaData() {
15
+ if (cachedMetaData)
16
+ return cachedMetaData;
17
+ const commands = await loadAll();
18
+ for (const command of commands)
19
+ cachedCommands.set(command.commandName, command);
20
+ cachedMetaData = commands.map((command) => command.serialize());
21
+ return cachedMetaData;
22
+ }
23
+ /**
24
+ * Ace command loader contract: resolves the command class for the given metadata.
25
+ */
26
+ export async function getCommand(metaData) {
27
+ if (cachedCommands.size === 0)
28
+ await getMetaData();
29
+ return cachedCommands.get(metaData.commandName) ?? null;
30
+ }
31
+ //# sourceMappingURL=main.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.js","sourceRoot":"","sources":["../../commands/main.ts"],"names":[],"mappings":"AAKA,MAAM,OAAO,GAAoD;IAC/D,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;IAC5B,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC;CAChC,CAAA;AAED,IAAI,cAA6C,CAAA;AACjD,MAAM,cAAc,GAAG,IAAI,GAAG,EAAwB,CAAA;AAEtD,KAAK,UAAU,OAAO;IACpB,OAAO,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAA;AACzE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,cAAc;QAAE,OAAO,cAAc,CAAA;IACzC,MAAM,QAAQ,GAAG,MAAM,OAAO,EAAE,CAAA;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ;QAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;IAChF,cAAc,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAA;IAC/D,OAAO,cAAc,CAAA;AACvB,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,QAA8C;IAC7E,IAAI,cAAc,CAAC,IAAI,KAAK,CAAC;QAAE,MAAM,WAAW,EAAE,CAAA;IAClD,OAAO,cAAc,CAAC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,IAAI,CAAA;AACzD,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '@adonisjs/core/ace';
2
+ import type { CommandOptions } from '@adonisjs/core/types/ace';
3
+ export default class MakeAiAgentCommand extends BaseCommand {
4
+ static commandName: string;
5
+ static description: string;
6
+ static options: CommandOptions;
7
+ name: string;
8
+ provider: string;
9
+ model: string;
10
+ maxTokens: number;
11
+ run(): Promise<void>;
12
+ }
13
+ //# sourceMappingURL=make_agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make_agent.d.ts","sourceRoot":"","sources":["../../commands/make_agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAe,MAAM,oBAAoB,CAAA;AAC7D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAI9D,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,WAAW;IACzD,MAAM,CAAC,WAAW,SAAkB;IACpC,MAAM,CAAC,WAAW,SAAqD;IAEvE,MAAM,CAAC,OAAO,EAAE,cAAc,CAE7B;IAGO,IAAI,EAAE,MAAM,CAAA;IAGZ,QAAQ,EAAE,MAAM,CAAA;IAGhB,KAAK,EAAE,MAAM,CAAA;IAGb,SAAS,EAAE,MAAM,CAAA;IAEnB,GAAG;CAqFV"}
@@ -0,0 +1,116 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ import { BaseCommand, args, flags } from '@adonisjs/core/ace';
11
+ import fs from 'node:fs/promises';
12
+ import path from 'node:path';
13
+ export default class MakeAiAgentCommand extends BaseCommand {
14
+ static commandName = 'make:ai-agent';
15
+ static description = 'Scaffold a production-grade typed AI Agent class';
16
+ static options = {
17
+ startApp: false,
18
+ };
19
+ async run() {
20
+ const rawName = this.name.replace(/Agent$/i, '');
21
+ const className = rawName.charAt(0).toUpperCase() + rawName.slice(1) + 'Agent';
22
+ const fileName = rawName.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase() + '_agent.ts';
23
+ const targetDir = path.join(this.app.makePath('app/ai/agents'));
24
+ await fs.mkdir(targetDir, { recursive: true });
25
+ const targetFile = path.join(targetDir, fileName);
26
+ const exists = await fs
27
+ .access(targetFile)
28
+ .then(() => true)
29
+ .catch(() => false);
30
+ if (exists) {
31
+ this.ui.logger.error(`Agent file already exists: ${targetFile}`);
32
+ return;
33
+ }
34
+ const template = `import ai from 'adonis-ai-kit/services/main'
35
+ import type { GenerateTextResult, StreamTextResult } from 'adonis-ai-kit/types'
36
+
37
+ export interface ${className}Input {
38
+ prompt: string
39
+ context?: Record<string, unknown>
40
+ }
41
+
42
+ /**
43
+ * ${className}
44
+ * Production-ready AI agent with token budgeting and structured execution.
45
+ */
46
+ export class ${className} {
47
+ public readonly agentName = '${rawName.toLowerCase()}-agent'
48
+ public readonly defaultProvider = ${this.provider ? `'${this.provider}'` : 'undefined'}
49
+ public readonly defaultModel = ${this.model ? `'${this.model}'` : 'undefined'}
50
+ public readonly maxOutputTokens = ${this.maxTokens}
51
+
52
+ /**
53
+ * System prompt establishing role, instructions, and guardrails.
54
+ */
55
+ protected getSystemPrompt(): string {
56
+ return [
57
+ 'You are ${className}, an expert AI assistant.',
58
+ 'Provide concise, accurate, and actionable answers.',
59
+ 'Always follow system security guidelines.',
60
+ ].join('\\n')
61
+ }
62
+
63
+ /**
64
+ * Executes synchronous text generation.
65
+ */
66
+ async run(input: ${className}Input): Promise<GenerateTextResult> {
67
+ return ai.generateText({
68
+ agentName: this.agentName,
69
+ provider: this.defaultProvider,
70
+ model: this.defaultModel,
71
+ maxOutputTokens: this.maxOutputTokens,
72
+ system: this.getSystemPrompt(),
73
+ prompt: input.prompt,
74
+ metadata: input.context,
75
+ })
76
+ }
77
+
78
+ /**
79
+ * Streams response in real time (e.g. for Server-Sent Events or WebSockets).
80
+ */
81
+ async stream(input: ${className}Input): Promise<StreamTextResult> {
82
+ return ai.streamText({
83
+ agentName: this.agentName,
84
+ provider: this.defaultProvider,
85
+ model: this.defaultModel,
86
+ maxOutputTokens: this.maxOutputTokens,
87
+ system: this.getSystemPrompt(),
88
+ prompt: input.prompt,
89
+ metadata: input.context,
90
+ })
91
+ }
92
+ }
93
+
94
+ export default new ${className}()
95
+ `;
96
+ await fs.writeFile(targetFile, template.trim() + '\n', 'utf8');
97
+ this.ui.logger.success(`Created AI Agent: ${targetFile}`);
98
+ }
99
+ }
100
+ __decorate([
101
+ args.string({ description: 'Name of the AI Agent class (e.g. MarketAnalysis, SupportChat, Coder)' }),
102
+ __metadata("design:type", String)
103
+ ], MakeAiAgentCommand.prototype, "name", void 0);
104
+ __decorate([
105
+ flags.string({ description: 'AI provider to use (default: app default)', default: '' }),
106
+ __metadata("design:type", String)
107
+ ], MakeAiAgentCommand.prototype, "provider", void 0);
108
+ __decorate([
109
+ flags.string({ description: 'Model to use (e.g. gpt-4o, claude-3-7-sonnet-latest)', default: '' }),
110
+ __metadata("design:type", String)
111
+ ], MakeAiAgentCommand.prototype, "model", void 0);
112
+ __decorate([
113
+ flags.number({ description: 'Max token budget per request', default: 2048 }),
114
+ __metadata("design:type", Number)
115
+ ], MakeAiAgentCommand.prototype, "maxTokens", void 0);
116
+ //# sourceMappingURL=make_agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"make_agent.js","sourceRoot":"","sources":["../../commands/make_agent.ts"],"names":[],"mappings":";;;;;;;;;AAAA,OAAO,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE7D,OAAO,EAAE,MAAM,kBAAkB,CAAA;AACjC,OAAO,IAAI,MAAM,WAAW,CAAA;AAE5B,MAAM,CAAC,OAAO,OAAO,kBAAmB,SAAQ,WAAW;IACzD,MAAM,CAAC,WAAW,GAAG,eAAe,CAAA;IACpC,MAAM,CAAC,WAAW,GAAG,kDAAkD,CAAA;IAEvE,MAAM,CAAC,OAAO,GAAmB;QAC/B,QAAQ,EAAE,KAAK;KAChB,CAAA;IAcD,KAAK,CAAC,GAAG;QACP,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAA;QAChD,MAAM,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,OAAO,CAAA;QAC9E,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,oBAAoB,EAAE,OAAO,CAAC,CAAC,WAAW,EAAE,GAAG,WAAW,CAAA;QAE3F,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC,CAAA;QAC/D,MAAM,EAAE,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;QAC9C,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAA;QAEjD,MAAM,MAAM,GAAG,MAAM,EAAE;aACpB,MAAM,CAAC,UAAU,CAAC;aAClB,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC;aAChB,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;QAErB,IAAI,MAAM,EAAE,CAAC;YACX,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,8BAA8B,UAAU,EAAE,CAAC,CAAA;YAChE,OAAM;QACR,CAAC;QAED,MAAM,QAAQ,GAAG;;;mBAGF,SAAS;;;;;;KAMvB,SAAS;;;eAGC,SAAS;iCACS,OAAO,CAAC,WAAW,EAAE;sCAChB,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,WAAW;mCACrD,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,WAAW;sCACzC,IAAI,CAAC,SAAS;;;;;;;iBAOnC,SAAS;;;;;;;;;qBASL,SAAS;;;;;;;;;;;;;;;wBAeN,SAAS;;;;;;;;;;;;;qBAaZ,SAAS;CAC7B,CAAA;QAEG,MAAM,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;QAC9D,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,qBAAqB,UAAU,EAAE,CAAC,CAAA;IAC3D,CAAC;;AA/FO;IADP,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,sEAAsE,EAAE,CAAC;;gDACjF;AAGZ;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,2CAA2C,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;;oDAChE;AAGhB;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,sDAAsD,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;;iDAC9E;AAGb;IADP,KAAK,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,8BAA8B,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;;qDACpD"}