language-operator 0.1.30 → 0.1.35

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -8
  3. data/CHANGELOG.md +49 -0
  4. data/CI_STATUS.md +56 -0
  5. data/Gemfile.lock +2 -2
  6. data/Makefile +28 -7
  7. data/Rakefile +29 -0
  8. data/docs/dsl/SCHEMA_VERSION.md +250 -0
  9. data/docs/dsl/agent-reference.md +13 -0
  10. data/lib/language_operator/agent/base.rb +10 -6
  11. data/lib/language_operator/agent/executor.rb +19 -97
  12. data/lib/language_operator/agent/safety/ast_validator.rb +62 -43
  13. data/lib/language_operator/agent/safety/safe_executor.rb +39 -2
  14. data/lib/language_operator/agent/scheduler.rb +60 -0
  15. data/lib/language_operator/agent/task_executor.rb +548 -0
  16. data/lib/language_operator/agent.rb +90 -27
  17. data/lib/language_operator/cli/base_command.rb +117 -0
  18. data/lib/language_operator/cli/commands/agent.rb +351 -466
  19. data/lib/language_operator/cli/commands/cluster.rb +276 -256
  20. data/lib/language_operator/cli/commands/install.rb +110 -119
  21. data/lib/language_operator/cli/commands/model.rb +284 -184
  22. data/lib/language_operator/cli/commands/persona.rb +220 -289
  23. data/lib/language_operator/cli/commands/quickstart.rb +4 -5
  24. data/lib/language_operator/cli/commands/status.rb +36 -53
  25. data/lib/language_operator/cli/commands/system.rb +760 -0
  26. data/lib/language_operator/cli/commands/tool.rb +356 -422
  27. data/lib/language_operator/cli/commands/use.rb +19 -22
  28. data/lib/language_operator/cli/formatters/code_formatter.rb +3 -7
  29. data/lib/language_operator/cli/formatters/log_formatter.rb +3 -5
  30. data/lib/language_operator/cli/formatters/progress_formatter.rb +3 -7
  31. data/lib/language_operator/cli/formatters/status_formatter.rb +37 -0
  32. data/lib/language_operator/cli/formatters/table_formatter.rb +10 -26
  33. data/lib/language_operator/cli/helpers/pastel_helper.rb +24 -0
  34. data/lib/language_operator/cli/helpers/resource_dependency_checker.rb +0 -18
  35. data/lib/language_operator/cli/main.rb +4 -0
  36. data/lib/language_operator/cli/wizards/quickstart_wizard.rb +0 -1
  37. data/lib/language_operator/client/config.rb +20 -21
  38. data/lib/language_operator/config.rb +115 -3
  39. data/lib/language_operator/constants.rb +54 -0
  40. data/lib/language_operator/dsl/agent_context.rb +7 -7
  41. data/lib/language_operator/dsl/agent_definition.rb +111 -26
  42. data/lib/language_operator/dsl/config.rb +30 -66
  43. data/lib/language_operator/dsl/main_definition.rb +114 -0
  44. data/lib/language_operator/dsl/schema.rb +1143 -0
  45. data/lib/language_operator/dsl/task_definition.rb +315 -0
  46. data/lib/language_operator/dsl.rb +1 -1
  47. data/lib/language_operator/instrumentation/task_tracer.rb +285 -0
  48. data/lib/language_operator/logger.rb +4 -4
  49. data/lib/language_operator/synthesis_test_harness.rb +324 -0
  50. data/lib/language_operator/templates/README.md +23 -0
  51. data/lib/language_operator/templates/examples/agent_synthesis.tmpl +133 -0
  52. data/lib/language_operator/templates/examples/persona_distillation.tmpl +19 -0
  53. data/lib/language_operator/templates/schema/.gitkeep +0 -0
  54. data/lib/language_operator/templates/schema/CHANGELOG.md +119 -0
  55. data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +306 -0
  56. data/lib/language_operator/templates/schema/agent_dsl_schema.json +494 -0
  57. data/lib/language_operator/type_coercion.rb +250 -0
  58. data/lib/language_operator/ux/base.rb +81 -0
  59. data/lib/language_operator/ux/concerns/README.md +155 -0
  60. data/lib/language_operator/ux/concerns/headings.rb +90 -0
  61. data/lib/language_operator/ux/concerns/input_validation.rb +146 -0
  62. data/lib/language_operator/ux/concerns/provider_helpers.rb +167 -0
  63. data/lib/language_operator/ux/create_agent.rb +252 -0
  64. data/lib/language_operator/ux/create_model.rb +267 -0
  65. data/lib/language_operator/ux/quickstart.rb +594 -0
  66. data/lib/language_operator/version.rb +1 -1
  67. data/lib/language_operator.rb +2 -0
  68. data/requirements/ARCHITECTURE.md +1 -0
  69. data/requirements/SCRATCH.md +153 -0
  70. data/requirements/dsl.md +0 -0
  71. data/requirements/features +1 -0
  72. data/requirements/personas +1 -0
  73. data/requirements/proposals +1 -0
  74. data/requirements/tasks/iterate.md +14 -15
  75. data/requirements/tasks/optimize.md +13 -4
  76. data/synth/001/Makefile +90 -0
  77. data/synth/001/agent.rb +26 -0
  78. data/synth/001/agent.yaml +7 -0
  79. data/synth/001/output.log +44 -0
  80. data/synth/Makefile +39 -0
  81. data/synth/README.md +342 -0
  82. metadata +49 -18
  83. data/examples/README.md +0 -569
  84. data/examples/agent_example.rb +0 -86
  85. data/examples/chat_endpoint_agent.rb +0 -118
  86. data/examples/github_webhook_agent.rb +0 -171
  87. data/examples/mcp_agent.rb +0 -158
  88. data/examples/oauth_callback_agent.rb +0 -296
  89. data/examples/stripe_webhook_agent.rb +0 -219
  90. data/examples/webhook_agent.rb +0 -80
  91. data/lib/language_operator/dsl/workflow_definition.rb +0 -259
  92. data/test_agent_dsl.rb +0 -108
@@ -0,0 +1,1143 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../version'
4
+ require_relative '../constants'
5
+
6
+ module LanguageOperator
7
+ module Dsl
8
+ # JSON Schema generator for the Agent DSL
9
+ #
10
+ # Generates a JSON Schema v7 representation of the Language Operator Agent DSL.
11
+ # This schema documents all available DSL methods, their parameters, validation
12
+ # patterns, and structure.
13
+ #
14
+ # Used for:
15
+ # - Template validation
16
+ # - Documentation generation
17
+ # - IDE autocomplete/IntelliSense
18
+ # - CLI introspection commands
19
+ #
20
+ # @example Generate schema
21
+ # schema = LanguageOperator::Dsl::Schema.to_json_schema
22
+ # File.write('schema.json', JSON.pretty_generate(schema))
23
+ # rubocop:disable Metrics/ClassLength
24
+ class Schema
25
+ # Generate complete JSON Schema v7 representation
26
+ #
27
+ # @return [Hash] JSON Schema draft-07 compliant schema
28
+ def self.to_json_schema
29
+ {
30
+ '$schema': 'http://json-schema.org/draft-07/schema#',
31
+ '$id': 'https://github.com/language-operator/language-operator-gem/schema/agent-dsl.json',
32
+ title: 'Language Operator Agent DSL',
33
+ description: 'Schema for defining autonomous AI agents using the Language Operator DSL',
34
+ version: LanguageOperator::VERSION,
35
+ type: 'object',
36
+ properties: agent_properties,
37
+ required: %w[name],
38
+ definitions: all_definitions
39
+ }
40
+ end
41
+
42
+ # Generate OpenAPI 3.0 specification for agent HTTP endpoints
43
+ #
44
+ # Generates an OpenAPI 3.0.3 spec documenting the HTTP API exposed by
45
+ # reactive agents. This includes chat endpoints, webhooks, and health checks.
46
+ #
47
+ # @return [Hash] OpenAPI 3.0.3 compliant specification
48
+ # @example Generate OpenAPI spec
49
+ # spec = LanguageOperator::Dsl::Schema.to_openapi
50
+ # File.write('openapi.json', JSON.pretty_generate(spec))
51
+ def self.to_openapi
52
+ {
53
+ openapi: '3.0.3',
54
+ info: openapi_info,
55
+ servers: openapi_servers,
56
+ paths: openapi_paths,
57
+ components: openapi_components
58
+ }
59
+ end
60
+
61
+ # Returns the schema version
62
+ #
63
+ # The schema version is directly linked to the gem version and follows semantic
64
+ # versioning. Schema changes follow these rules:
65
+ # - MAJOR: Breaking changes to DSL structure or behavior
66
+ # - MINOR: New features, backward-compatible additions
67
+ # - PATCH: Bug fixes, documentation improvements
68
+ #
69
+ # @return [String] Current schema version (e.g., "0.1.30")
70
+ # @example
71
+ # LanguageOperator::Dsl::Schema.version
72
+ # # => "0.1.30"
73
+ def self.version
74
+ LanguageOperator::VERSION
75
+ end
76
+
77
+ # Returns array of safe agent DSL methods allowed in agent definitions
78
+ #
79
+ # Reads from Agent::Safety::ASTValidator::SAFE_AGENT_METHODS constant.
80
+ # These methods are validated as safe for use in synthesized agent code.
81
+ #
82
+ # Includes methods for:
83
+ # - Agent metadata (description, persona, objectives)
84
+ # - Execution modes (mode, schedule)
85
+ # - Workflows (workflow, step, depends_on, prompt)
86
+ # - Constraints (budget, max_requests, rate_limit, content_filter)
87
+ # - Output destinations (output)
88
+ # - Endpoints (webhook, as_mcp_server, as_chat_endpoint)
89
+ #
90
+ # @return [Array<String>] Sorted array of safe agent method names
91
+ # @example
92
+ # LanguageOperator::Dsl::Schema.safe_agent_methods
93
+ # # => ["agent", "as_chat_endpoint", "as_mcp_server", "budget", ...]
94
+ def self.safe_agent_methods
95
+ require_relative '../agent/safety/ast_validator'
96
+ Agent::Safety::ASTValidator::SAFE_AGENT_METHODS.sort
97
+ end
98
+
99
+ # Returns array of safe tool DSL methods allowed in tool definitions
100
+ #
101
+ # Reads from Agent::Safety::ASTValidator::SAFE_TOOL_METHODS constant.
102
+ # These methods are validated as safe for use in synthesized tool code.
103
+ #
104
+ # Includes methods for:
105
+ # - Tool definition (tool, description)
106
+ # - Parameters (parameter, type, required, default)
107
+ # - Execution (execute)
108
+ #
109
+ # @return [Array<String>] Sorted array of safe tool method names
110
+ # @example
111
+ # LanguageOperator::Dsl::Schema.safe_tool_methods
112
+ # # => ["default", "description", "execute", "parameter", "required", "tool", "type"]
113
+ def self.safe_tool_methods
114
+ require_relative '../agent/safety/ast_validator'
115
+ Agent::Safety::ASTValidator::SAFE_TOOL_METHODS.sort
116
+ end
117
+
118
+ # Returns array of safe helper methods available in execute blocks
119
+ #
120
+ # Reads from Agent::Safety::ASTValidator::SAFE_HELPER_METHODS constant.
121
+ # These helper methods are validated as safe for use in tool execute blocks.
122
+ #
123
+ # Includes helpers for:
124
+ # - HTTP requests (HTTP.*)
125
+ # - Shell commands (Shell.run)
126
+ # - Validation (validate_url, validate_phone, validate_email)
127
+ # - Environment variables (env_required, env_get)
128
+ # - Utilities (truncate, parse_csv)
129
+ # - Response formatting (error, success)
130
+ #
131
+ # @return [Array<String>] Sorted array of safe helper method names
132
+ # @example
133
+ # LanguageOperator::Dsl::Schema.safe_helper_methods
134
+ # # => ["HTTP", "Shell", "env_get", "env_required", "error", ...]
135
+ def self.safe_helper_methods
136
+ require_relative '../agent/safety/ast_validator'
137
+ Agent::Safety::ASTValidator::SAFE_HELPER_METHODS.sort
138
+ end
139
+
140
+ # Agent top-level properties
141
+ #
142
+ # @return [Hash] Schema properties for agent definition
143
+ def self.agent_properties
144
+ {
145
+ name: {
146
+ type: 'string',
147
+ description: 'Unique agent identifier (lowercase, alphanumeric, hyphens)',
148
+ pattern: '^[a-z0-9-]+$',
149
+ minLength: 1,
150
+ maxLength: 63
151
+ },
152
+ description: {
153
+ type: 'string',
154
+ description: 'Human-readable description of agent purpose'
155
+ },
156
+ persona: {
157
+ type: 'string',
158
+ description: 'System prompt or persona defining agent behavior and expertise'
159
+ },
160
+ schedule: {
161
+ type: 'string',
162
+ description: 'Cron expression for scheduled execution (sets mode to :scheduled)',
163
+ pattern: '^\s*(\S+\s+){4}\S+\s*$'
164
+ },
165
+ mode: {
166
+ type: 'string',
167
+ description: 'Execution mode for the agent',
168
+ enum: Constants::PRIMARY_MODES
169
+ },
170
+ objectives: {
171
+ type: 'array',
172
+ description: 'List of goals the agent should achieve',
173
+ items: {
174
+ type: 'string'
175
+ },
176
+ minItems: 0
177
+ },
178
+ # DSL v1 (task/main model)
179
+ tasks: {
180
+ type: 'array',
181
+ description: 'Task definitions (organic functions with stable contracts)',
182
+ items: {
183
+ '$ref': '#/definitions/TaskDefinition'
184
+ }
185
+ },
186
+ main: {
187
+ '$ref': '#/definitions/MainDefinition',
188
+ description: 'Main execution block (imperative entry point)'
189
+ },
190
+ # Common properties
191
+ constraints: {
192
+ '$ref': '#/definitions/ConstraintsDefinition'
193
+ },
194
+ output: {
195
+ '$ref': '#/definitions/OutputDefinition'
196
+ },
197
+ webhooks: {
198
+ type: 'array',
199
+ description: 'Webhook endpoints for reactive agents',
200
+ items: {
201
+ '$ref': '#/definitions/WebhookDefinition'
202
+ }
203
+ },
204
+ mcp_server: {
205
+ '$ref': '#/definitions/McpServerDefinition'
206
+ },
207
+ chat_endpoint: {
208
+ '$ref': '#/definitions/ChatEndpointDefinition'
209
+ }
210
+ }
211
+ end
212
+
213
+ # All nested definition schemas
214
+ #
215
+ # @return [Hash] Schema definitions for nested types
216
+ def self.all_definitions
217
+ {
218
+ # DSL v1 (task/main model)
219
+ TaskDefinition: task_definition_schema,
220
+ MainDefinition: main_definition_schema,
221
+ TypeSchema: type_schema_definition,
222
+ # Common definitions
223
+ ConstraintsDefinition: constraints_definition_schema,
224
+ OutputDefinition: output_definition_schema,
225
+ WebhookDefinition: webhook_definition_schema,
226
+ WebhookAuthentication: webhook_authentication_schema,
227
+ McpServerDefinition: mcp_server_definition_schema,
228
+ ChatEndpointDefinition: chat_endpoint_definition_schema,
229
+ ToolDefinition: tool_definition_schema,
230
+ ParameterDefinition: parameter_definition_schema
231
+ }
232
+ end
233
+
234
+ # Task definition schema (DSL v1)
235
+ #
236
+ # @return [Hash] Schema for task definitions (organic functions)
237
+ def self.task_definition_schema
238
+ {
239
+ type: 'object',
240
+ description: 'Organic function with stable contract (inputs/outputs) and evolving implementation',
241
+ properties: {
242
+ name: {
243
+ type: 'string',
244
+ description: 'Task identifier (symbol)',
245
+ pattern: '^[a-z_][a-z0-9_]*$'
246
+ },
247
+ inputs: {
248
+ '$ref': '#/definitions/TypeSchema',
249
+ description: 'Input contract (parameter types)'
250
+ },
251
+ outputs: {
252
+ '$ref': '#/definitions/TypeSchema',
253
+ description: 'Output contract (return value types)'
254
+ },
255
+ instructions: {
256
+ type: 'string',
257
+ description: 'Natural language instructions for neural implementation (optional)'
258
+ },
259
+ implementation_type: {
260
+ type: 'string',
261
+ description: 'Implementation approach',
262
+ enum: %w[neural symbolic hybrid undefined]
263
+ }
264
+ },
265
+ required: %w[name inputs outputs]
266
+ }
267
+ end
268
+
269
+ # Main definition schema (DSL v1)
270
+ #
271
+ # @return [Hash] Schema for main execution block
272
+ def self.main_definition_schema
273
+ {
274
+ type: 'object',
275
+ description: 'Imperative entry point for agent execution',
276
+ properties: {
277
+ type: {
278
+ type: 'string',
279
+ description: 'Block type',
280
+ enum: ['main']
281
+ },
282
+ description: {
283
+ type: 'string',
284
+ description: 'Main block executes tasks using execute_task() with Ruby control flow'
285
+ }
286
+ },
287
+ additionalProperties: false
288
+ }
289
+ end
290
+
291
+ # Type schema definition (DSL v1)
292
+ #
293
+ # @return [Hash] Schema for type schemas used in task inputs/outputs
294
+ def self.type_schema_definition
295
+ {
296
+ type: 'object',
297
+ description: 'Type schema for task contract validation',
298
+ patternProperties: {
299
+ '^[a-z_][a-z0-9_]*$': {
300
+ type: 'string',
301
+ description: 'Parameter type',
302
+ enum: %w[string integer number boolean array hash any]
303
+ }
304
+ },
305
+ additionalProperties: false,
306
+ examples: [
307
+ {
308
+ user_id: 'integer',
309
+ name: 'string',
310
+ active: 'boolean'
311
+ },
312
+ {
313
+ data: 'array',
314
+ metadata: 'hash'
315
+ }
316
+ ]
317
+ }
318
+ end
319
+
320
+ # Constraints definition schema
321
+ #
322
+ # @return [Hash] Schema for constraint definitions
323
+ def self.constraints_definition_schema
324
+ {
325
+ type: 'object',
326
+ description: 'Execution constraints and limits',
327
+ properties: {
328
+ max_iterations: {
329
+ type: 'integer',
330
+ description: 'Maximum number of execution iterations',
331
+ minimum: 1
332
+ },
333
+ timeout: {
334
+ type: 'string',
335
+ description: 'Execution timeout (e.g., "30s", "5m", "1h")',
336
+ pattern: '^\d+[smh]$'
337
+ },
338
+ memory: {
339
+ type: 'string',
340
+ description: 'Memory limit (e.g., "512Mi", "1Gi")'
341
+ },
342
+ rate_limit: {
343
+ type: 'integer',
344
+ description: 'Maximum requests per time period',
345
+ minimum: 1
346
+ },
347
+ daily_budget: {
348
+ type: 'number',
349
+ description: 'Maximum daily cost in USD',
350
+ minimum: 0
351
+ },
352
+ hourly_budget: {
353
+ type: 'number',
354
+ description: 'Maximum hourly cost in USD',
355
+ minimum: 0
356
+ },
357
+ token_budget: {
358
+ type: 'integer',
359
+ description: 'Maximum total tokens allowed',
360
+ minimum: 1
361
+ },
362
+ requests_per_minute: {
363
+ type: 'integer',
364
+ description: 'Maximum requests per minute',
365
+ minimum: 1
366
+ },
367
+ requests_per_hour: {
368
+ type: 'integer',
369
+ description: 'Maximum requests per hour',
370
+ minimum: 1
371
+ },
372
+ requests_per_day: {
373
+ type: 'integer',
374
+ description: 'Maximum requests per day',
375
+ minimum: 1
376
+ },
377
+ blocked_patterns: {
378
+ type: 'array',
379
+ description: 'Content patterns to block',
380
+ items: { type: 'string' }
381
+ },
382
+ blocked_topics: {
383
+ type: 'array',
384
+ description: 'Topics to avoid',
385
+ items: { type: 'string' }
386
+ }
387
+ }
388
+ }
389
+ end
390
+
391
+ # Output definition schema
392
+ #
393
+ # @return [Hash] Schema for output configuration
394
+ def self.output_definition_schema
395
+ {
396
+ type: 'object',
397
+ description: 'Output destination configuration',
398
+ properties: {
399
+ workspace: {
400
+ type: 'string',
401
+ description: 'Workspace directory path for file outputs'
402
+ },
403
+ slack: {
404
+ type: 'object',
405
+ description: 'Slack integration configuration',
406
+ properties: {
407
+ channel: {
408
+ type: 'string',
409
+ description: 'Slack channel name or ID'
410
+ }
411
+ },
412
+ required: %w[channel]
413
+ },
414
+ email: {
415
+ type: 'object',
416
+ description: 'Email notification configuration',
417
+ properties: {
418
+ to: {
419
+ type: 'string',
420
+ description: 'Email recipient address',
421
+ format: 'email'
422
+ }
423
+ },
424
+ required: %w[to]
425
+ }
426
+ }
427
+ }
428
+ end
429
+
430
+ # Webhook definition schema
431
+ #
432
+ # @return [Hash] Schema for webhook definitions
433
+ def self.webhook_definition_schema
434
+ {
435
+ type: 'object',
436
+ description: 'Webhook endpoint configuration',
437
+ properties: {
438
+ path: {
439
+ type: 'string',
440
+ description: 'URL path for webhook endpoint',
441
+ pattern: '^/'
442
+ },
443
+ method: {
444
+ type: 'string',
445
+ description: 'HTTP method',
446
+ enum: %w[get post put delete patch],
447
+ default: 'post'
448
+ },
449
+ authentication: {
450
+ '$ref': '#/definitions/WebhookAuthentication'
451
+ },
452
+ validations: {
453
+ type: 'array',
454
+ description: 'Request validation rules',
455
+ items: {
456
+ type: 'object',
457
+ properties: {
458
+ type: {
459
+ type: 'string',
460
+ enum: %w[headers content_type custom]
461
+ }
462
+ }
463
+ }
464
+ }
465
+ },
466
+ required: %w[path]
467
+ }
468
+ end
469
+
470
+ # Webhook authentication schema
471
+ #
472
+ # @return [Hash] Schema for webhook authentication
473
+ def self.webhook_authentication_schema
474
+ {
475
+ type: 'object',
476
+ description: 'Webhook authentication configuration',
477
+ properties: {
478
+ type: {
479
+ type: 'string',
480
+ description: 'Authentication type',
481
+ enum: %w[hmac api_key bearer custom]
482
+ },
483
+ secret: {
484
+ type: 'string',
485
+ description: 'Secret key for authentication'
486
+ },
487
+ header: {
488
+ type: 'string',
489
+ description: 'Header name containing signature/token'
490
+ },
491
+ algorithm: {
492
+ type: 'string',
493
+ description: 'HMAC algorithm',
494
+ enum: %w[sha1 sha256 sha512]
495
+ },
496
+ prefix: {
497
+ type: 'string',
498
+ description: 'Signature prefix (e.g., "sha256=")'
499
+ }
500
+ }
501
+ }
502
+ end
503
+
504
+ # MCP server definition schema
505
+ #
506
+ # @return [Hash] Schema for MCP server definitions
507
+ def self.mcp_server_definition_schema
508
+ {
509
+ type: 'object',
510
+ description: 'MCP (Model Context Protocol) server configuration',
511
+ properties: {
512
+ name: {
513
+ type: 'string',
514
+ description: 'MCP server name'
515
+ },
516
+ tools: {
517
+ type: 'object',
518
+ description: 'Tools exposed via MCP',
519
+ additionalProperties: {
520
+ '$ref': '#/definitions/ToolDefinition'
521
+ }
522
+ }
523
+ }
524
+ }
525
+ end
526
+
527
+ # Chat endpoint definition schema
528
+ #
529
+ # @return [Hash] Schema for chat endpoint definitions
530
+ def self.chat_endpoint_definition_schema
531
+ {
532
+ type: 'object',
533
+ description: 'OpenAI-compatible chat endpoint configuration',
534
+ properties: {
535
+ system_prompt: {
536
+ type: 'string',
537
+ description: 'System prompt for chat mode'
538
+ },
539
+ temperature: {
540
+ type: 'number',
541
+ description: 'Sampling temperature (0.0-2.0)',
542
+ minimum: 0.0,
543
+ maximum: 2.0,
544
+ default: 0.7
545
+ },
546
+ max_tokens: {
547
+ type: 'integer',
548
+ description: 'Maximum tokens in response',
549
+ minimum: 1,
550
+ default: 2000
551
+ },
552
+ model_name: {
553
+ type: 'string',
554
+ description: 'Model name exposed in API'
555
+ },
556
+ top_p: {
557
+ type: 'number',
558
+ description: 'Nucleus sampling parameter (0.0-1.0)',
559
+ minimum: 0.0,
560
+ maximum: 1.0,
561
+ default: 1.0
562
+ },
563
+ frequency_penalty: {
564
+ type: 'number',
565
+ description: 'Frequency penalty (-2.0 to 2.0)',
566
+ minimum: -2.0,
567
+ maximum: 2.0,
568
+ default: 0.0
569
+ },
570
+ presence_penalty: {
571
+ type: 'number',
572
+ description: 'Presence penalty (-2.0 to 2.0)',
573
+ minimum: -2.0,
574
+ maximum: 2.0,
575
+ default: 0.0
576
+ },
577
+ stop_sequences: {
578
+ type: 'array',
579
+ description: 'Sequences that stop generation',
580
+ items: { type: 'string' }
581
+ }
582
+ }
583
+ }
584
+ end
585
+
586
+ # Tool definition schema
587
+ #
588
+ # @return [Hash] Schema for tool definitions
589
+ def self.tool_definition_schema
590
+ {
591
+ type: 'object',
592
+ description: 'MCP tool definition',
593
+ properties: {
594
+ name: {
595
+ type: 'string',
596
+ description: 'Tool name (lowercase, alphanumeric, underscores)',
597
+ pattern: '^[a-z0-9_]+$'
598
+ },
599
+ description: {
600
+ type: 'string',
601
+ description: 'Human-readable tool description'
602
+ },
603
+ parameters: {
604
+ type: 'object',
605
+ description: 'Tool parameters',
606
+ additionalProperties: {
607
+ '$ref': '#/definitions/ParameterDefinition'
608
+ }
609
+ }
610
+ },
611
+ required: %w[name description]
612
+ }
613
+ end
614
+
615
+ # Parameter definition schema
616
+ #
617
+ # @return [Hash] Schema for parameter definitions
618
+ def self.parameter_definition_schema
619
+ {
620
+ type: 'object',
621
+ description: 'Tool parameter definition',
622
+ properties: {
623
+ type: {
624
+ type: 'string',
625
+ description: 'Parameter type',
626
+ enum: %w[string number integer boolean array object]
627
+ },
628
+ description: {
629
+ type: 'string',
630
+ description: 'Parameter description'
631
+ },
632
+ required: {
633
+ type: 'boolean',
634
+ description: 'Whether parameter is required',
635
+ default: false
636
+ },
637
+ default: {
638
+ description: 'Default value if not provided'
639
+ },
640
+ enum: {
641
+ type: 'array',
642
+ description: 'Allowed values',
643
+ items: {}
644
+ }
645
+ },
646
+ required: %w[type]
647
+ }
648
+ end
649
+
650
+ # OpenAPI info section
651
+ #
652
+ # @return [Hash] OpenAPI info object
653
+ def self.openapi_info
654
+ {
655
+ title: 'Language Operator Agent API',
656
+ version: LanguageOperator::VERSION,
657
+ description: 'HTTP API endpoints exposed by Language Operator reactive agents',
658
+ contact: {
659
+ name: 'Language Operator',
660
+ url: 'https://github.com/language-operator/language-operator-gem'
661
+ },
662
+ license: {
663
+ name: 'FSL-1.1-Apache-2.0',
664
+ url: 'https://github.com/language-operator/language-operator-gem/blob/main/LICENSE'
665
+ }
666
+ }
667
+ end
668
+
669
+ # OpenAPI servers section
670
+ #
671
+ # @return [Array<Hash>] OpenAPI server objects
672
+ def self.openapi_servers
673
+ [
674
+ {
675
+ url: 'http://localhost:8080',
676
+ description: 'Local development server'
677
+ }
678
+ ]
679
+ end
680
+
681
+ # OpenAPI paths section - documents all HTTP endpoints
682
+ #
683
+ # @return [Hash] OpenAPI paths object
684
+ def self.openapi_paths
685
+ {
686
+ '/health' => health_endpoint_spec,
687
+ '/ready' => ready_endpoint_spec,
688
+ '/v1/chat/completions' => chat_completions_endpoint_spec,
689
+ '/v1/models' => models_endpoint_spec
690
+ }
691
+ end
692
+
693
+ # OpenAPI components section - reusable schemas
694
+ #
695
+ # @return [Hash] OpenAPI components object
696
+ def self.openapi_components
697
+ {
698
+ schemas: {
699
+ ChatCompletionRequest: chat_completion_request_schema,
700
+ ChatCompletionResponse: chat_completion_response_schema,
701
+ ChatMessage: chat_message_schema,
702
+ ChatChoice: chat_choice_schema,
703
+ ChatUsage: chat_usage_schema,
704
+ ModelList: model_list_schema,
705
+ Model: model_schema,
706
+ HealthResponse: health_response_schema,
707
+ ErrorResponse: error_response_schema
708
+ }
709
+ }
710
+ end
711
+
712
+ # Health check endpoint spec
713
+ #
714
+ # @return [Hash] OpenAPI path item
715
+ def self.health_endpoint_spec
716
+ {
717
+ get: {
718
+ summary: 'Health check',
719
+ description: 'Returns the health status of the agent',
720
+ operationId: 'getHealth',
721
+ tags: ['Health'],
722
+ responses: {
723
+ '200': {
724
+ description: 'Agent is healthy',
725
+ content: {
726
+ 'application/json': {
727
+ schema: {
728
+ '$ref': '#/components/schemas/HealthResponse'
729
+ }
730
+ }
731
+ }
732
+ }
733
+ }
734
+ }
735
+ }
736
+ end
737
+
738
+ # Readiness check endpoint spec
739
+ #
740
+ # @return [Hash] OpenAPI path item
741
+ def self.ready_endpoint_spec
742
+ {
743
+ get: {
744
+ summary: 'Readiness check',
745
+ description: 'Returns whether the agent is ready to accept requests',
746
+ operationId: 'getReady',
747
+ tags: ['Health'],
748
+ responses: {
749
+ '200': {
750
+ description: 'Agent is ready',
751
+ content: {
752
+ 'application/json': {
753
+ schema: {
754
+ '$ref': '#/components/schemas/HealthResponse'
755
+ }
756
+ }
757
+ }
758
+ },
759
+ '503': {
760
+ description: 'Agent is not ready',
761
+ content: {
762
+ 'application/json': {
763
+ schema: {
764
+ '$ref': '#/components/schemas/ErrorResponse'
765
+ }
766
+ }
767
+ }
768
+ }
769
+ }
770
+ }
771
+ }
772
+ end
773
+
774
+ # Chat completions endpoint spec (OpenAI-compatible)
775
+ #
776
+ # @return [Hash] OpenAPI path item
777
+ def self.chat_completions_endpoint_spec
778
+ {
779
+ post: {
780
+ summary: 'Create chat completion',
781
+ description: 'Creates a chat completion response (OpenAI-compatible endpoint)',
782
+ operationId: 'createChatCompletion',
783
+ tags: ['Chat'],
784
+ requestBody: {
785
+ required: true,
786
+ content: {
787
+ 'application/json': {
788
+ schema: {
789
+ '$ref': '#/components/schemas/ChatCompletionRequest'
790
+ }
791
+ }
792
+ }
793
+ },
794
+ responses: {
795
+ '200': {
796
+ description: 'Successful chat completion response',
797
+ content: {
798
+ 'application/json': {
799
+ schema: {
800
+ '$ref': '#/components/schemas/ChatCompletionResponse'
801
+ }
802
+ },
803
+ 'text/event-stream': {
804
+ description: 'Server-sent events stream (when stream=true)',
805
+ schema: {
806
+ type: 'string'
807
+ }
808
+ }
809
+ }
810
+ },
811
+ '400': {
812
+ description: 'Invalid request',
813
+ content: {
814
+ 'application/json': {
815
+ schema: {
816
+ '$ref': '#/components/schemas/ErrorResponse'
817
+ }
818
+ }
819
+ }
820
+ }
821
+ }
822
+ }
823
+ }
824
+ end
825
+
826
+ # Models list endpoint spec (OpenAI-compatible)
827
+ #
828
+ # @return [Hash] OpenAPI path item
829
+ def self.models_endpoint_spec
830
+ {
831
+ get: {
832
+ summary: 'List models',
833
+ description: 'Lists available models (OpenAI-compatible endpoint)',
834
+ operationId: 'listModels',
835
+ tags: ['Models'],
836
+ responses: {
837
+ '200': {
838
+ description: 'List of available models',
839
+ content: {
840
+ 'application/json': {
841
+ schema: {
842
+ '$ref': '#/components/schemas/ModelList'
843
+ }
844
+ }
845
+ }
846
+ }
847
+ }
848
+ }
849
+ }
850
+ end
851
+
852
+ # Chat completion request schema
853
+ #
854
+ # @return [Hash] OpenAPI schema object
855
+ def self.chat_completion_request_schema
856
+ {
857
+ type: 'object',
858
+ required: %w[model messages],
859
+ properties: {
860
+ model: {
861
+ type: 'string',
862
+ description: 'Model name to use for completion'
863
+ },
864
+ messages: {
865
+ type: 'array',
866
+ description: 'List of messages in the conversation',
867
+ items: {
868
+ '$ref': '#/components/schemas/ChatMessage'
869
+ }
870
+ },
871
+ temperature: {
872
+ type: 'number',
873
+ description: 'Sampling temperature (0.0-2.0)',
874
+ minimum: 0.0,
875
+ maximum: 2.0,
876
+ default: 0.7
877
+ },
878
+ max_tokens: {
879
+ type: 'integer',
880
+ description: 'Maximum tokens in response',
881
+ minimum: 1,
882
+ default: 2000
883
+ },
884
+ stream: {
885
+ type: 'boolean',
886
+ description: 'Stream responses as server-sent events',
887
+ default: false
888
+ },
889
+ top_p: {
890
+ type: 'number',
891
+ description: 'Nucleus sampling parameter',
892
+ minimum: 0.0,
893
+ maximum: 1.0,
894
+ default: 1.0
895
+ },
896
+ frequency_penalty: {
897
+ type: 'number',
898
+ description: 'Frequency penalty (-2.0 to 2.0)',
899
+ minimum: -2.0,
900
+ maximum: 2.0,
901
+ default: 0.0
902
+ },
903
+ presence_penalty: {
904
+ type: 'number',
905
+ description: 'Presence penalty (-2.0 to 2.0)',
906
+ minimum: -2.0,
907
+ maximum: 2.0,
908
+ default: 0.0
909
+ },
910
+ stop: {
911
+ oneOf: [
912
+ { type: 'string' },
913
+ {
914
+ type: 'array',
915
+ items: { type: 'string' }
916
+ }
917
+ ],
918
+ description: 'Stop sequences for generation'
919
+ }
920
+ }
921
+ }
922
+ end
923
+
924
+ # Chat completion response schema
925
+ #
926
+ # @return [Hash] OpenAPI schema object
927
+ def self.chat_completion_response_schema
928
+ {
929
+ type: 'object',
930
+ required: %w[id object created model choices],
931
+ properties: {
932
+ id: {
933
+ type: 'string',
934
+ description: 'Unique identifier for the completion'
935
+ },
936
+ object: {
937
+ type: 'string',
938
+ description: 'Object type (always "chat.completion")',
939
+ enum: ['chat.completion']
940
+ },
941
+ created: {
942
+ type: 'integer',
943
+ description: 'Unix timestamp of creation'
944
+ },
945
+ model: {
946
+ type: 'string',
947
+ description: 'Model used for completion'
948
+ },
949
+ choices: {
950
+ type: 'array',
951
+ description: 'List of completion choices',
952
+ items: {
953
+ '$ref': '#/components/schemas/ChatChoice'
954
+ }
955
+ },
956
+ usage: {
957
+ '$ref': '#/components/schemas/ChatUsage'
958
+ }
959
+ }
960
+ }
961
+ end
962
+
963
+ # Chat message schema
964
+ #
965
+ # @return [Hash] OpenAPI schema object
966
+ def self.chat_message_schema
967
+ {
968
+ type: 'object',
969
+ required: %w[role content],
970
+ properties: {
971
+ role: {
972
+ type: 'string',
973
+ description: 'Message role',
974
+ enum: %w[system user assistant]
975
+ },
976
+ content: {
977
+ type: 'string',
978
+ description: 'Message content'
979
+ },
980
+ name: {
981
+ type: 'string',
982
+ description: 'Optional name of the message author'
983
+ }
984
+ }
985
+ }
986
+ end
987
+
988
+ # Chat choice schema
989
+ #
990
+ # @return [Hash] OpenAPI schema object
991
+ def self.chat_choice_schema
992
+ {
993
+ type: 'object',
994
+ required: %w[index message finish_reason],
995
+ properties: {
996
+ index: {
997
+ type: 'integer',
998
+ description: 'Choice index'
999
+ },
1000
+ message: {
1001
+ '$ref': '#/components/schemas/ChatMessage'
1002
+ },
1003
+ finish_reason: {
1004
+ type: 'string',
1005
+ description: 'Reason for completion finish',
1006
+ enum: %w[stop length content_filter null]
1007
+ }
1008
+ }
1009
+ }
1010
+ end
1011
+
1012
+ # Chat usage schema
1013
+ #
1014
+ # @return [Hash] OpenAPI schema object
1015
+ def self.chat_usage_schema
1016
+ {
1017
+ type: 'object',
1018
+ required: %w[prompt_tokens completion_tokens total_tokens],
1019
+ properties: {
1020
+ prompt_tokens: {
1021
+ type: 'integer',
1022
+ description: 'Tokens in the prompt'
1023
+ },
1024
+ completion_tokens: {
1025
+ type: 'integer',
1026
+ description: 'Tokens in the completion'
1027
+ },
1028
+ total_tokens: {
1029
+ type: 'integer',
1030
+ description: 'Total tokens used'
1031
+ }
1032
+ }
1033
+ }
1034
+ end
1035
+
1036
+ # Model list schema
1037
+ #
1038
+ # @return [Hash] OpenAPI schema object
1039
+ def self.model_list_schema
1040
+ {
1041
+ type: 'object',
1042
+ required: %w[object data],
1043
+ properties: {
1044
+ object: {
1045
+ type: 'string',
1046
+ description: 'Object type (always "list")',
1047
+ enum: ['list']
1048
+ },
1049
+ data: {
1050
+ type: 'array',
1051
+ description: 'List of available models',
1052
+ items: {
1053
+ '$ref': '#/components/schemas/Model'
1054
+ }
1055
+ }
1056
+ }
1057
+ }
1058
+ end
1059
+
1060
+ # Model schema
1061
+ #
1062
+ # @return [Hash] OpenAPI schema object
1063
+ def self.model_schema
1064
+ {
1065
+ type: 'object',
1066
+ required: %w[id object],
1067
+ properties: {
1068
+ id: {
1069
+ type: 'string',
1070
+ description: 'Model identifier'
1071
+ },
1072
+ object: {
1073
+ type: 'string',
1074
+ description: 'Object type (always "model")',
1075
+ enum: ['model']
1076
+ },
1077
+ created: {
1078
+ type: 'integer',
1079
+ description: 'Unix timestamp of model creation'
1080
+ },
1081
+ owned_by: {
1082
+ type: 'string',
1083
+ description: 'Organization that owns the model'
1084
+ }
1085
+ }
1086
+ }
1087
+ end
1088
+
1089
+ # Health response schema
1090
+ #
1091
+ # @return [Hash] OpenAPI schema object
1092
+ def self.health_response_schema
1093
+ {
1094
+ type: 'object',
1095
+ required: %w[status],
1096
+ properties: {
1097
+ status: {
1098
+ type: 'string',
1099
+ description: 'Health status',
1100
+ enum: %w[ok ready]
1101
+ },
1102
+ timestamp: {
1103
+ type: 'string',
1104
+ format: 'date-time',
1105
+ description: 'Timestamp of health check'
1106
+ }
1107
+ }
1108
+ }
1109
+ end
1110
+
1111
+ # Error response schema
1112
+ #
1113
+ # @return [Hash] OpenAPI schema object
1114
+ def self.error_response_schema
1115
+ {
1116
+ type: 'object',
1117
+ required: %w[error],
1118
+ properties: {
1119
+ error: {
1120
+ type: 'object',
1121
+ required: %w[message type],
1122
+ properties: {
1123
+ message: {
1124
+ type: 'string',
1125
+ description: 'Error message'
1126
+ },
1127
+ type: {
1128
+ type: 'string',
1129
+ description: 'Error type'
1130
+ },
1131
+ code: {
1132
+ type: 'string',
1133
+ description: 'Error code'
1134
+ }
1135
+ }
1136
+ }
1137
+ }
1138
+ }
1139
+ end
1140
+ end
1141
+ # rubocop:enable Metrics/ClassLength
1142
+ end
1143
+ end