elsabro 2.3.0 → 3.7.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 (67) hide show
  1. package/README.md +668 -20
  2. package/bin/install.js +0 -0
  3. package/flows/development-flow.json +452 -0
  4. package/flows/quick-flow.json +118 -0
  5. package/package.json +3 -2
  6. package/references/SYSTEM_INDEX.md +379 -5
  7. package/references/agent-marketplace.md +2274 -0
  8. package/references/agent-protocol.md +1126 -0
  9. package/references/ai-code-suggestions.md +2413 -0
  10. package/references/checkpointing.md +595 -0
  11. package/references/collaboration-patterns.md +851 -0
  12. package/references/collaborative-sessions.md +1081 -0
  13. package/references/configuration-management.md +1810 -0
  14. package/references/cost-tracking.md +1095 -0
  15. package/references/enterprise-sso.md +2001 -0
  16. package/references/error-contracts-v2.md +968 -0
  17. package/references/event-driven.md +1031 -0
  18. package/references/flow-orchestration.md +940 -0
  19. package/references/flow-visualization.md +1557 -0
  20. package/references/ide-integrations.md +3513 -0
  21. package/references/interrupt-system.md +681 -0
  22. package/references/kubernetes-deployment.md +3099 -0
  23. package/references/memory-system.md +683 -0
  24. package/references/mobile-companion.md +3236 -0
  25. package/references/multi-llm-providers.md +2494 -0
  26. package/references/multi-project-memory.md +1182 -0
  27. package/references/observability.md +793 -0
  28. package/references/output-schemas.md +858 -0
  29. package/references/performance-profiler.md +955 -0
  30. package/references/plugin-system.md +1526 -0
  31. package/references/prompt-management.md +292 -0
  32. package/references/sandbox-execution.md +303 -0
  33. package/references/security-system.md +1253 -0
  34. package/references/streaming.md +696 -0
  35. package/references/testing-framework.md +1151 -0
  36. package/references/time-travel.md +802 -0
  37. package/references/tool-registry.md +886 -0
  38. package/references/voice-commands.md +3296 -0
  39. package/templates/agent-marketplace-config.json +220 -0
  40. package/templates/agent-protocol-config.json +136 -0
  41. package/templates/ai-suggestions-config.json +100 -0
  42. package/templates/checkpoint-state.json +61 -0
  43. package/templates/collaboration-config.json +157 -0
  44. package/templates/collaborative-sessions-config.json +153 -0
  45. package/templates/configuration-config.json +245 -0
  46. package/templates/cost-tracking-config.json +148 -0
  47. package/templates/enterprise-sso-config.json +438 -0
  48. package/templates/events-config.json +148 -0
  49. package/templates/flow-visualization-config.json +196 -0
  50. package/templates/ide-integrations-config.json +442 -0
  51. package/templates/kubernetes-config.json +764 -0
  52. package/templates/memory-state.json +84 -0
  53. package/templates/mobile-companion-config.json +600 -0
  54. package/templates/multi-llm-config.json +544 -0
  55. package/templates/multi-project-memory-config.json +145 -0
  56. package/templates/observability-config.json +109 -0
  57. package/templates/performance-profiler-config.json +125 -0
  58. package/templates/plugin-config.json +170 -0
  59. package/templates/prompt-management-config.json +86 -0
  60. package/templates/sandbox-config.json +185 -0
  61. package/templates/schemas-config.json +65 -0
  62. package/templates/security-config.json +120 -0
  63. package/templates/streaming-config.json +72 -0
  64. package/templates/testing-config.json +81 -0
  65. package/templates/timetravel-config.json +62 -0
  66. package/templates/tool-registry-config.json +109 -0
  67. package/templates/voice-commands-config.json +658 -0
@@ -0,0 +1,1126 @@
1
+ # Agent Protocol REST API (v3.2)
2
+
3
+ Sistema de interoperabilidad basado en el estándar Agent Protocol para comunicación con otros frameworks de agentes.
4
+
5
+ ## Arquitectura
6
+
7
+ ```
8
+ ┌─────────────────────────────────────────────────────────────────────────┐
9
+ │ AGENT PROTOCOL LAYER │
10
+ ├─────────────────────────────────────────────────────────────────────────┤
11
+ │ │
12
+ │ ┌─────────────────────────────────────────────────────────────────┐ │
13
+ │ │ REST API SERVER │ │
14
+ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │ │
15
+ │ │ │ /tasks │ │ /steps │ │/artifacts│ │ /agent-info │ │ │
16
+ │ │ │ CRUD │ │ CRUD │ │ CRUD │ │ metadata │ │ │
17
+ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────────────┘ │ │
18
+ │ └─────────────────────────────────────────────────────────────────┘ │
19
+ │ │ │
20
+ │ ▼ │
21
+ │ ┌─────────────────────────────────────────────────────────────────┐ │
22
+ │ │ PROTOCOL ADAPTER │ │
23
+ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌────────────────┐ │ │
24
+ │ │ │ Task Mapper │ │ Step Mapper │ │ Artifact Store │ │ │
25
+ │ │ │ Protocol↔ELSABRO│ │ Protocol↔Flow │ │ File-based │ │ │
26
+ │ │ └─────────────────┘ └─────────────────┘ └────────────────┘ │ │
27
+ │ └─────────────────────────────────────────────────────────────────┘ │
28
+ │ │ │
29
+ │ ▼ │
30
+ │ ┌─────────────────────────────────────────────────────────────────┐ │
31
+ │ │ ELSABRO CORE SYSTEMS │ │
32
+ │ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────────────┐ │ │
33
+ │ │ │ Tasks │ │ Flows │ │ Agents │ │ Checkpoints │ │ │
34
+ │ │ │ API │ │ Engine │ │ Pool │ │ System │ │ │
35
+ │ │ └─────────┘ └─────────┘ └─────────┘ └─────────────────┘ │ │
36
+ │ └─────────────────────────────────────────────────────────────────┘ │
37
+ │ │
38
+ └─────────────────────────────────────────────────────────────────────────┘
39
+ ```
40
+
41
+ ---
42
+
43
+ ## Especificación OpenAPI
44
+
45
+ ```yaml
46
+ openapi: 3.1.0
47
+ info:
48
+ title: ELSABRO Agent Protocol API
49
+ version: 1.0.0
50
+ description: Agent Protocol implementation for ELSABRO framework interoperability
51
+
52
+ servers:
53
+ - url: http://localhost:8080/api/v1
54
+ description: Local development server
55
+
56
+ paths:
57
+ /agent:
58
+ get:
59
+ summary: Get agent information
60
+ operationId: getAgentInfo
61
+ responses:
62
+ '200':
63
+ description: Agent information
64
+ content:
65
+ application/json:
66
+ schema:
67
+ $ref: '#/components/schemas/AgentInfo'
68
+
69
+ /tasks:
70
+ get:
71
+ summary: List all tasks
72
+ operationId: listTasks
73
+ parameters:
74
+ - name: status
75
+ in: query
76
+ schema:
77
+ type: string
78
+ enum: [pending, in_progress, completed, failed]
79
+ - name: limit
80
+ in: query
81
+ schema:
82
+ type: integer
83
+ default: 50
84
+ - name: offset
85
+ in: query
86
+ schema:
87
+ type: integer
88
+ default: 0
89
+ responses:
90
+ '200':
91
+ description: List of tasks
92
+ content:
93
+ application/json:
94
+ schema:
95
+ $ref: '#/components/schemas/TaskList'
96
+
97
+ post:
98
+ summary: Create a new task
99
+ operationId: createTask
100
+ requestBody:
101
+ required: true
102
+ content:
103
+ application/json:
104
+ schema:
105
+ $ref: '#/components/schemas/TaskCreate'
106
+ responses:
107
+ '201':
108
+ description: Task created
109
+ content:
110
+ application/json:
111
+ schema:
112
+ $ref: '#/components/schemas/Task'
113
+
114
+ /tasks/{taskId}:
115
+ get:
116
+ summary: Get task details
117
+ operationId: getTask
118
+ parameters:
119
+ - name: taskId
120
+ in: path
121
+ required: true
122
+ schema:
123
+ type: string
124
+ responses:
125
+ '200':
126
+ description: Task details
127
+ content:
128
+ application/json:
129
+ schema:
130
+ $ref: '#/components/schemas/Task'
131
+ '404':
132
+ description: Task not found
133
+
134
+ /tasks/{taskId}/steps:
135
+ get:
136
+ summary: List task steps
137
+ operationId: listSteps
138
+ parameters:
139
+ - name: taskId
140
+ in: path
141
+ required: true
142
+ schema:
143
+ type: string
144
+ responses:
145
+ '200':
146
+ description: List of steps
147
+ content:
148
+ application/json:
149
+ schema:
150
+ $ref: '#/components/schemas/StepList'
151
+
152
+ post:
153
+ summary: Execute next step
154
+ operationId: executeStep
155
+ parameters:
156
+ - name: taskId
157
+ in: path
158
+ required: true
159
+ schema:
160
+ type: string
161
+ requestBody:
162
+ content:
163
+ application/json:
164
+ schema:
165
+ $ref: '#/components/schemas/StepRequest'
166
+ responses:
167
+ '200':
168
+ description: Step executed
169
+ content:
170
+ application/json:
171
+ schema:
172
+ $ref: '#/components/schemas/Step'
173
+
174
+ /tasks/{taskId}/steps/{stepId}:
175
+ get:
176
+ summary: Get step details
177
+ operationId: getStep
178
+ parameters:
179
+ - name: taskId
180
+ in: path
181
+ required: true
182
+ schema:
183
+ type: string
184
+ - name: stepId
185
+ in: path
186
+ required: true
187
+ schema:
188
+ type: string
189
+ responses:
190
+ '200':
191
+ description: Step details
192
+ content:
193
+ application/json:
194
+ schema:
195
+ $ref: '#/components/schemas/Step'
196
+
197
+ /tasks/{taskId}/artifacts:
198
+ get:
199
+ summary: List task artifacts
200
+ operationId: listArtifacts
201
+ parameters:
202
+ - name: taskId
203
+ in: path
204
+ required: true
205
+ schema:
206
+ type: string
207
+ responses:
208
+ '200':
209
+ description: List of artifacts
210
+ content:
211
+ application/json:
212
+ schema:
213
+ $ref: '#/components/schemas/ArtifactList'
214
+
215
+ post:
216
+ summary: Upload artifact
217
+ operationId: uploadArtifact
218
+ parameters:
219
+ - name: taskId
220
+ in: path
221
+ required: true
222
+ schema:
223
+ type: string
224
+ requestBody:
225
+ required: true
226
+ content:
227
+ multipart/form-data:
228
+ schema:
229
+ type: object
230
+ properties:
231
+ file:
232
+ type: string
233
+ format: binary
234
+ relative_path:
235
+ type: string
236
+ responses:
237
+ '201':
238
+ description: Artifact uploaded
239
+ content:
240
+ application/json:
241
+ schema:
242
+ $ref: '#/components/schemas/Artifact'
243
+
244
+ /tasks/{taskId}/artifacts/{artifactId}:
245
+ get:
246
+ summary: Download artifact
247
+ operationId: downloadArtifact
248
+ parameters:
249
+ - name: taskId
250
+ in: path
251
+ required: true
252
+ schema:
253
+ type: string
254
+ - name: artifactId
255
+ in: path
256
+ required: true
257
+ schema:
258
+ type: string
259
+ responses:
260
+ '200':
261
+ description: Artifact content
262
+ content:
263
+ application/octet-stream:
264
+ schema:
265
+ type: string
266
+ format: binary
267
+
268
+ components:
269
+ schemas:
270
+ AgentInfo:
271
+ type: object
272
+ required:
273
+ - name
274
+ - version
275
+ - protocol_version
276
+ properties:
277
+ name:
278
+ type: string
279
+ example: "ELSABRO"
280
+ version:
281
+ type: string
282
+ example: "3.2.0"
283
+ protocol_version:
284
+ type: string
285
+ example: "1.0.0"
286
+ description:
287
+ type: string
288
+ capabilities:
289
+ type: array
290
+ items:
291
+ type: string
292
+ example:
293
+ - "checkpointing"
294
+ - "memory"
295
+ - "flows"
296
+ - "time-travel"
297
+ - "streaming"
298
+
299
+ TaskCreate:
300
+ type: object
301
+ required:
302
+ - input
303
+ properties:
304
+ input:
305
+ type: string
306
+ description: Task input/prompt
307
+ additional_input:
308
+ type: object
309
+ description: Additional parameters
310
+
311
+ Task:
312
+ type: object
313
+ required:
314
+ - task_id
315
+ - input
316
+ - status
317
+ - created_at
318
+ properties:
319
+ task_id:
320
+ type: string
321
+ input:
322
+ type: string
323
+ additional_input:
324
+ type: object
325
+ status:
326
+ type: string
327
+ enum: [pending, in_progress, completed, failed]
328
+ output:
329
+ type: string
330
+ additional_output:
331
+ type: object
332
+ artifacts:
333
+ type: array
334
+ items:
335
+ $ref: '#/components/schemas/Artifact'
336
+ created_at:
337
+ type: string
338
+ format: date-time
339
+ updated_at:
340
+ type: string
341
+ format: date-time
342
+
343
+ TaskList:
344
+ type: object
345
+ properties:
346
+ tasks:
347
+ type: array
348
+ items:
349
+ $ref: '#/components/schemas/Task'
350
+ total:
351
+ type: integer
352
+ has_more:
353
+ type: boolean
354
+
355
+ StepRequest:
356
+ type: object
357
+ properties:
358
+ input:
359
+ type: string
360
+ additional_input:
361
+ type: object
362
+
363
+ Step:
364
+ type: object
365
+ required:
366
+ - step_id
367
+ - task_id
368
+ - status
369
+ - created_at
370
+ properties:
371
+ step_id:
372
+ type: string
373
+ task_id:
374
+ type: string
375
+ name:
376
+ type: string
377
+ status:
378
+ type: string
379
+ enum: [pending, running, completed, failed]
380
+ input:
381
+ type: string
382
+ output:
383
+ type: string
384
+ additional_output:
385
+ type: object
386
+ artifacts:
387
+ type: array
388
+ items:
389
+ $ref: '#/components/schemas/Artifact'
390
+ is_last:
391
+ type: boolean
392
+ created_at:
393
+ type: string
394
+ format: date-time
395
+ completed_at:
396
+ type: string
397
+ format: date-time
398
+
399
+ StepList:
400
+ type: object
401
+ properties:
402
+ steps:
403
+ type: array
404
+ items:
405
+ $ref: '#/components/schemas/Step'
406
+ total:
407
+ type: integer
408
+
409
+ Artifact:
410
+ type: object
411
+ required:
412
+ - artifact_id
413
+ - file_name
414
+ - created_at
415
+ properties:
416
+ artifact_id:
417
+ type: string
418
+ file_name:
419
+ type: string
420
+ relative_path:
421
+ type: string
422
+ content_type:
423
+ type: string
424
+ size_bytes:
425
+ type: integer
426
+ created_at:
427
+ type: string
428
+ format: date-time
429
+
430
+ ArtifactList:
431
+ type: object
432
+ properties:
433
+ artifacts:
434
+ type: array
435
+ items:
436
+ $ref: '#/components/schemas/Artifact'
437
+ total:
438
+ type: integer
439
+ ```
440
+
441
+ ---
442
+
443
+ ## Implementación del Servidor
444
+
445
+ ### AgentProtocolServer
446
+
447
+ ```typescript
448
+ class AgentProtocolServer {
449
+ private port: number;
450
+ private taskMapper: TaskMapper;
451
+ private stepMapper: StepMapper;
452
+ private artifactStore: ArtifactStore;
453
+
454
+ constructor(config: AgentProtocolConfig) {
455
+ this.port = config.port || 8080;
456
+ this.taskMapper = new TaskMapper();
457
+ this.stepMapper = new StepMapper();
458
+ this.artifactStore = new ArtifactStore(config.artifactsDir);
459
+ }
460
+
461
+ // GET /agent
462
+ async getAgentInfo(): Promise<AgentInfo> {
463
+ return {
464
+ name: "ELSABRO",
465
+ version: "3.2.0",
466
+ protocol_version: "1.0.0",
467
+ description: "AI-powered development orchestration framework",
468
+ capabilities: [
469
+ "checkpointing",
470
+ "multi-level-memory",
471
+ "flow-orchestration",
472
+ "error-contracts",
473
+ "interrupts",
474
+ "observability",
475
+ "streaming",
476
+ "output-schemas",
477
+ "time-travel",
478
+ "agent-protocol"
479
+ ]
480
+ };
481
+ }
482
+
483
+ // POST /tasks
484
+ async createTask(request: TaskCreate): Promise<Task> {
485
+ // Map to ELSABRO task
486
+ const elsabroTask = await this.taskMapper.fromProtocol(request);
487
+
488
+ // Create in Tasks API
489
+ const taskId = await TaskCreate({
490
+ subject: this.extractSubject(request.input),
491
+ description: request.input,
492
+ metadata: {
493
+ protocol: "agent-protocol",
494
+ additional_input: request.additional_input
495
+ }
496
+ });
497
+
498
+ return this.taskMapper.toProtocol(elsabroTask, taskId);
499
+ }
500
+
501
+ // GET /tasks
502
+ async listTasks(options: ListOptions): Promise<TaskList> {
503
+ const tasks = await TaskList();
504
+
505
+ // Filter by status if provided
506
+ let filtered = tasks;
507
+ if (options.status) {
508
+ filtered = tasks.filter(t =>
509
+ this.mapStatus(t.status) === options.status
510
+ );
511
+ }
512
+
513
+ // Pagination
514
+ const offset = options.offset || 0;
515
+ const limit = options.limit || 50;
516
+ const paginated = filtered.slice(offset, offset + limit);
517
+
518
+ return {
519
+ tasks: paginated.map(t => this.taskMapper.toProtocol(t)),
520
+ total: filtered.length,
521
+ has_more: offset + limit < filtered.length
522
+ };
523
+ }
524
+
525
+ // GET /tasks/:taskId
526
+ async getTask(taskId: string): Promise<Task | null> {
527
+ const task = await TaskGet({ taskId });
528
+ if (!task) return null;
529
+ return this.taskMapper.toProtocol(task);
530
+ }
531
+
532
+ // POST /tasks/:taskId/steps
533
+ async executeStep(taskId: string, request: StepRequest): Promise<Step> {
534
+ const task = await TaskGet({ taskId });
535
+ if (!task) throw new NotFoundError('Task not found');
536
+
537
+ // Get current flow state
538
+ const flowState = await this.getFlowState(taskId);
539
+
540
+ // Execute next node in flow
541
+ const result = await FlowEngine.executeNext(flowState, {
542
+ input: request.input,
543
+ additional_input: request.additional_input
544
+ });
545
+
546
+ // Map to protocol step
547
+ const step = this.stepMapper.toProtocol(result, taskId);
548
+
549
+ // Create checkpoint after step
550
+ await CheckpointManager.save({
551
+ type: 'auto',
552
+ reason: `Step ${step.step_id} completed`
553
+ });
554
+
555
+ return step;
556
+ }
557
+
558
+ // GET /tasks/:taskId/steps
559
+ async listSteps(taskId: string): Promise<StepList> {
560
+ const task = await TaskGet({ taskId });
561
+ if (!task) throw new NotFoundError('Task not found');
562
+
563
+ // Get flow execution history
564
+ const history = await this.getFlowHistory(taskId);
565
+
566
+ return {
567
+ steps: history.map((h, i) => this.stepMapper.toProtocol(h, taskId, i)),
568
+ total: history.length
569
+ };
570
+ }
571
+
572
+ // GET /tasks/:taskId/steps/:stepId
573
+ async getStep(taskId: string, stepId: string): Promise<Step | null> {
574
+ const history = await this.getFlowHistory(taskId);
575
+ const step = history.find(h => h.id === stepId);
576
+ if (!step) return null;
577
+ return this.stepMapper.toProtocol(step, taskId);
578
+ }
579
+
580
+ // POST /tasks/:taskId/artifacts
581
+ async uploadArtifact(
582
+ taskId: string,
583
+ file: Buffer,
584
+ filename: string,
585
+ relativePath?: string
586
+ ): Promise<Artifact> {
587
+ const artifact = await this.artifactStore.save(taskId, file, filename, relativePath);
588
+ return artifact;
589
+ }
590
+
591
+ // GET /tasks/:taskId/artifacts
592
+ async listArtifacts(taskId: string): Promise<ArtifactList> {
593
+ const artifacts = await this.artifactStore.list(taskId);
594
+ return {
595
+ artifacts,
596
+ total: artifacts.length
597
+ };
598
+ }
599
+
600
+ // GET /tasks/:taskId/artifacts/:artifactId
601
+ async downloadArtifact(taskId: string, artifactId: string): Promise<Buffer> {
602
+ return this.artifactStore.get(taskId, artifactId);
603
+ }
604
+
605
+ // Helper methods
606
+ private mapStatus(elsabroStatus: string): string {
607
+ const mapping: Record<string, string> = {
608
+ 'pending': 'pending',
609
+ 'in_progress': 'in_progress',
610
+ 'completed': 'completed',
611
+ 'failed': 'failed',
612
+ 'blocked': 'pending'
613
+ };
614
+ return mapping[elsabroStatus] || 'pending';
615
+ }
616
+
617
+ private extractSubject(input: string): string {
618
+ // Extract first line or first 100 chars
619
+ const firstLine = input.split('\n')[0];
620
+ return firstLine.length > 100 ? firstLine.slice(0, 100) + '...' : firstLine;
621
+ }
622
+
623
+ private async getFlowState(taskId: string): Promise<FlowState> {
624
+ // Load flow state from checkpoint or create new
625
+ const checkpoint = await CheckpointManager.getLatest(taskId);
626
+ if (checkpoint?.flow_state) {
627
+ return checkpoint.flow_state;
628
+ }
629
+ return FlowEngine.createState('development-flow');
630
+ }
631
+
632
+ private async getFlowHistory(taskId: string): Promise<FlowHistoryEntry[]> {
633
+ // Load execution history from checkpoints
634
+ const checkpoints = await CheckpointManager.list({ taskId });
635
+ return checkpoints.flatMap(cp => cp.history || []);
636
+ }
637
+ }
638
+ ```
639
+
640
+ ---
641
+
642
+ ## Mappers
643
+
644
+ ### TaskMapper
645
+
646
+ ```typescript
647
+ class TaskMapper {
648
+ // Convert Protocol Task to ELSABRO format
649
+ fromProtocol(protocolTask: TaskCreate): ElsabroTask {
650
+ return {
651
+ subject: this.extractSubject(protocolTask.input),
652
+ description: protocolTask.input,
653
+ metadata: {
654
+ type: 'protocol_task',
655
+ source: 'agent-protocol',
656
+ additional_input: protocolTask.additional_input || {}
657
+ }
658
+ };
659
+ }
660
+
661
+ // Convert ELSABRO Task to Protocol format
662
+ toProtocol(elsabroTask: ElsabroTask, taskId?: string): Task {
663
+ return {
664
+ task_id: taskId || elsabroTask.id,
665
+ input: elsabroTask.description,
666
+ additional_input: elsabroTask.metadata?.additional_input || {},
667
+ status: this.mapStatus(elsabroTask.status),
668
+ output: elsabroTask.result || null,
669
+ additional_output: elsabroTask.metadata?.output || {},
670
+ artifacts: [], // Populated separately
671
+ created_at: elsabroTask.created_at,
672
+ updated_at: elsabroTask.updated_at
673
+ };
674
+ }
675
+
676
+ private mapStatus(status: string): TaskStatus {
677
+ const mapping: Record<string, TaskStatus> = {
678
+ 'pending': 'pending',
679
+ 'in_progress': 'in_progress',
680
+ 'completed': 'completed',
681
+ 'failed': 'failed',
682
+ 'blocked': 'pending',
683
+ 'deleted': 'failed'
684
+ };
685
+ return mapping[status] || 'pending';
686
+ }
687
+
688
+ private extractSubject(input: string): string {
689
+ const firstLine = input.split('\n')[0].trim();
690
+ return firstLine.length > 100 ? firstLine.slice(0, 97) + '...' : firstLine;
691
+ }
692
+ }
693
+ ```
694
+
695
+ ### StepMapper
696
+
697
+ ```typescript
698
+ class StepMapper {
699
+ // Convert Flow node execution to Protocol Step
700
+ toProtocol(
701
+ flowResult: FlowNodeResult,
702
+ taskId: string,
703
+ index?: number
704
+ ): Step {
705
+ return {
706
+ step_id: flowResult.node_id || `step_${index}`,
707
+ task_id: taskId,
708
+ name: flowResult.node_name || `Step ${index + 1}`,
709
+ status: this.mapStatus(flowResult.status),
710
+ input: flowResult.input || '',
711
+ output: flowResult.output || '',
712
+ additional_output: {
713
+ agent: flowResult.agent,
714
+ model: flowResult.model,
715
+ duration_ms: flowResult.duration_ms,
716
+ tokens: flowResult.tokens
717
+ },
718
+ artifacts: flowResult.artifacts || [],
719
+ is_last: flowResult.is_terminal || false,
720
+ created_at: flowResult.started_at,
721
+ completed_at: flowResult.completed_at
722
+ };
723
+ }
724
+
725
+ private mapStatus(status: string): StepStatus {
726
+ const mapping: Record<string, StepStatus> = {
727
+ 'pending': 'pending',
728
+ 'running': 'running',
729
+ 'completed': 'completed',
730
+ 'failed': 'failed',
731
+ 'skipped': 'completed'
732
+ };
733
+ return mapping[status] || 'pending';
734
+ }
735
+ }
736
+ ```
737
+
738
+ ---
739
+
740
+ ## Artifact Store
741
+
742
+ ```typescript
743
+ class ArtifactStore {
744
+ private baseDir: string;
745
+
746
+ constructor(baseDir: string = '.elsabro/artifacts') {
747
+ this.baseDir = baseDir;
748
+ }
749
+
750
+ async save(
751
+ taskId: string,
752
+ content: Buffer,
753
+ filename: string,
754
+ relativePath?: string
755
+ ): Promise<Artifact> {
756
+ const artifactId = this.generateId();
757
+ const taskDir = path.join(this.baseDir, taskId);
758
+
759
+ // Ensure directory exists
760
+ await fs.mkdir(taskDir, { recursive: true });
761
+
762
+ // Determine final path
763
+ const finalPath = relativePath
764
+ ? path.join(taskDir, relativePath, filename)
765
+ : path.join(taskDir, filename);
766
+
767
+ // Ensure subdirectory exists if relativePath provided
768
+ if (relativePath) {
769
+ await fs.mkdir(path.dirname(finalPath), { recursive: true });
770
+ }
771
+
772
+ // Write file
773
+ await fs.writeFile(finalPath, content);
774
+
775
+ // Get content type
776
+ const contentType = this.getContentType(filename);
777
+
778
+ // Create artifact record
779
+ const artifact: Artifact = {
780
+ artifact_id: artifactId,
781
+ file_name: filename,
782
+ relative_path: relativePath || '',
783
+ content_type: contentType,
784
+ size_bytes: content.length,
785
+ created_at: new Date().toISOString()
786
+ };
787
+
788
+ // Save artifact metadata
789
+ await this.saveMetadata(taskId, artifact);
790
+
791
+ return artifact;
792
+ }
793
+
794
+ async get(taskId: string, artifactId: string): Promise<Buffer> {
795
+ const metadata = await this.getMetadata(taskId);
796
+ const artifact = metadata.find(a => a.artifact_id === artifactId);
797
+
798
+ if (!artifact) {
799
+ throw new NotFoundError('Artifact not found');
800
+ }
801
+
802
+ const filePath = path.join(
803
+ this.baseDir,
804
+ taskId,
805
+ artifact.relative_path,
806
+ artifact.file_name
807
+ );
808
+
809
+ return fs.readFile(filePath);
810
+ }
811
+
812
+ async list(taskId: string): Promise<Artifact[]> {
813
+ return this.getMetadata(taskId);
814
+ }
815
+
816
+ async delete(taskId: string, artifactId: string): Promise<void> {
817
+ const metadata = await this.getMetadata(taskId);
818
+ const artifact = metadata.find(a => a.artifact_id === artifactId);
819
+
820
+ if (!artifact) {
821
+ throw new NotFoundError('Artifact not found');
822
+ }
823
+
824
+ const filePath = path.join(
825
+ this.baseDir,
826
+ taskId,
827
+ artifact.relative_path,
828
+ artifact.file_name
829
+ );
830
+
831
+ await fs.unlink(filePath);
832
+ await this.removeMetadata(taskId, artifactId);
833
+ }
834
+
835
+ private generateId(): string {
836
+ return `art_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
837
+ }
838
+
839
+ private getContentType(filename: string): string {
840
+ const ext = path.extname(filename).toLowerCase();
841
+ const types: Record<string, string> = {
842
+ '.json': 'application/json',
843
+ '.md': 'text/markdown',
844
+ '.txt': 'text/plain',
845
+ '.ts': 'text/typescript',
846
+ '.js': 'text/javascript',
847
+ '.py': 'text/x-python',
848
+ '.html': 'text/html',
849
+ '.css': 'text/css',
850
+ '.png': 'image/png',
851
+ '.jpg': 'image/jpeg',
852
+ '.gif': 'image/gif',
853
+ '.pdf': 'application/pdf',
854
+ '.zip': 'application/zip'
855
+ };
856
+ return types[ext] || 'application/octet-stream';
857
+ }
858
+
859
+ private async getMetadataPath(taskId: string): Promise<string> {
860
+ return path.join(this.baseDir, taskId, '.artifacts.json');
861
+ }
862
+
863
+ private async getMetadata(taskId: string): Promise<Artifact[]> {
864
+ const metaPath = await this.getMetadataPath(taskId);
865
+ try {
866
+ const content = await fs.readFile(metaPath, 'utf-8');
867
+ return JSON.parse(content);
868
+ } catch {
869
+ return [];
870
+ }
871
+ }
872
+
873
+ private async saveMetadata(taskId: string, artifact: Artifact): Promise<void> {
874
+ const metadata = await this.getMetadata(taskId);
875
+ metadata.push(artifact);
876
+ const metaPath = await this.getMetadataPath(taskId);
877
+ await fs.writeFile(metaPath, JSON.stringify(metadata, null, 2));
878
+ }
879
+
880
+ private async removeMetadata(taskId: string, artifactId: string): Promise<void> {
881
+ const metadata = await this.getMetadata(taskId);
882
+ const filtered = metadata.filter(a => a.artifact_id !== artifactId);
883
+ const metaPath = await this.getMetadataPath(taskId);
884
+ await fs.writeFile(metaPath, JSON.stringify(filtered, null, 2));
885
+ }
886
+ }
887
+ ```
888
+
889
+ ---
890
+
891
+ ## Integración con ELSABRO
892
+
893
+ ### Uso desde Comandos
894
+
895
+ ```typescript
896
+ // En /elsabro:start - exponer API opcional
897
+ if (config.agentProtocol?.enabled) {
898
+ const server = new AgentProtocolServer(config.agentProtocol);
899
+ await server.start();
900
+ console.log(`Agent Protocol API running on port ${config.agentProtocol.port}`);
901
+ }
902
+ ```
903
+
904
+ ### Uso como Cliente
905
+
906
+ ```typescript
907
+ // Conectar a otro agente que implemente Agent Protocol
908
+ class AgentProtocolClient {
909
+ private baseUrl: string;
910
+
911
+ constructor(baseUrl: string) {
912
+ this.baseUrl = baseUrl;
913
+ }
914
+
915
+ async createTask(input: string): Promise<Task> {
916
+ const response = await fetch(`${this.baseUrl}/tasks`, {
917
+ method: 'POST',
918
+ headers: { 'Content-Type': 'application/json' },
919
+ body: JSON.stringify({ input })
920
+ });
921
+ return response.json();
922
+ }
923
+
924
+ async executeStep(taskId: string, input?: string): Promise<Step> {
925
+ const response = await fetch(`${this.baseUrl}/tasks/${taskId}/steps`, {
926
+ method: 'POST',
927
+ headers: { 'Content-Type': 'application/json' },
928
+ body: JSON.stringify({ input })
929
+ });
930
+ return response.json();
931
+ }
932
+
933
+ async runToCompletion(taskId: string): Promise<Task> {
934
+ let step: Step;
935
+ do {
936
+ step = await this.executeStep(taskId);
937
+ } while (!step.is_last);
938
+
939
+ return this.getTask(taskId);
940
+ }
941
+
942
+ async getTask(taskId: string): Promise<Task> {
943
+ const response = await fetch(`${this.baseUrl}/tasks/${taskId}`);
944
+ return response.json();
945
+ }
946
+
947
+ async getAgentInfo(): Promise<AgentInfo> {
948
+ const response = await fetch(`${this.baseUrl}/agent`);
949
+ return response.json();
950
+ }
951
+ }
952
+ ```
953
+
954
+ ---
955
+
956
+ ## WebSocket Streaming (Extensión)
957
+
958
+ Para soporte de streaming en tiempo real:
959
+
960
+ ```typescript
961
+ // WebSocket endpoint para streaming de steps
962
+ // ws://localhost:8080/ws/tasks/{taskId}/steps
963
+
964
+ interface StepStreamMessage {
965
+ type: 'step_started' | 'step_progress' | 'step_completed' | 'step_failed';
966
+ task_id: string;
967
+ step_id: string;
968
+ data: {
969
+ progress?: number;
970
+ output_chunk?: string;
971
+ error?: string;
972
+ step?: Step;
973
+ };
974
+ }
975
+
976
+ class AgentProtocolWebSocket {
977
+ private wss: WebSocketServer;
978
+ private connections: Map<string, Set<WebSocket>>;
979
+
980
+ constructor(server: http.Server) {
981
+ this.wss = new WebSocketServer({ server, path: '/ws' });
982
+ this.connections = new Map();
983
+
984
+ this.wss.on('connection', (ws, req) => {
985
+ const taskId = this.extractTaskId(req.url);
986
+ if (taskId) {
987
+ this.subscribe(taskId, ws);
988
+ ws.on('close', () => this.unsubscribe(taskId, ws));
989
+ }
990
+ });
991
+ }
992
+
993
+ subscribe(taskId: string, ws: WebSocket): void {
994
+ if (!this.connections.has(taskId)) {
995
+ this.connections.set(taskId, new Set());
996
+ }
997
+ this.connections.get(taskId)!.add(ws);
998
+ }
999
+
1000
+ unsubscribe(taskId: string, ws: WebSocket): void {
1001
+ this.connections.get(taskId)?.delete(ws);
1002
+ }
1003
+
1004
+ broadcast(taskId: string, message: StepStreamMessage): void {
1005
+ const sockets = this.connections.get(taskId);
1006
+ if (sockets) {
1007
+ const data = JSON.stringify(message);
1008
+ sockets.forEach(ws => {
1009
+ if (ws.readyState === WebSocket.OPEN) {
1010
+ ws.send(data);
1011
+ }
1012
+ });
1013
+ }
1014
+ }
1015
+
1016
+ // Emit from StreamManager integration
1017
+ emitProgress(taskId: string, stepId: string, progress: number): void {
1018
+ this.broadcast(taskId, {
1019
+ type: 'step_progress',
1020
+ task_id: taskId,
1021
+ step_id: stepId,
1022
+ data: { progress }
1023
+ });
1024
+ }
1025
+
1026
+ emitChunk(taskId: string, stepId: string, chunk: string): void {
1027
+ this.broadcast(taskId, {
1028
+ type: 'step_progress',
1029
+ task_id: taskId,
1030
+ step_id: stepId,
1031
+ data: { output_chunk: chunk }
1032
+ });
1033
+ }
1034
+
1035
+ private extractTaskId(url: string | undefined): string | null {
1036
+ if (!url) return null;
1037
+ const match = url.match(/\/tasks\/([^/]+)/);
1038
+ return match ? match[1] : null;
1039
+ }
1040
+ }
1041
+ ```
1042
+
1043
+ ---
1044
+
1045
+ ## Configuración
1046
+
1047
+ ```json
1048
+ {
1049
+ "agentProtocol": {
1050
+ "enabled": true,
1051
+ "port": 8080,
1052
+ "host": "localhost",
1053
+ "basePath": "/api/v1",
1054
+ "artifactsDir": ".elsabro/artifacts",
1055
+ "cors": {
1056
+ "enabled": true,
1057
+ "origins": ["*"]
1058
+ },
1059
+ "auth": {
1060
+ "enabled": false,
1061
+ "type": "bearer",
1062
+ "token": null
1063
+ },
1064
+ "websocket": {
1065
+ "enabled": true,
1066
+ "path": "/ws"
1067
+ },
1068
+ "rateLimit": {
1069
+ "enabled": true,
1070
+ "windowMs": 60000,
1071
+ "maxRequests": 100
1072
+ }
1073
+ }
1074
+ }
1075
+ ```
1076
+
1077
+ ---
1078
+
1079
+ ## Compatibilidad
1080
+
1081
+ ### Frameworks Compatibles
1082
+
1083
+ | Framework | Versión | Notas |
1084
+ |-----------|---------|-------|
1085
+ | Auto-GPT | 0.5+ | Full compatibility |
1086
+ | BabyAGI | Latest | Full compatibility |
1087
+ | AgentGPT | Latest | Full compatibility |
1088
+ | SuperAGI | Latest | Full compatibility |
1089
+ | Custom Agents | N/A | Implement protocol |
1090
+
1091
+ ### Limitaciones Conocidas
1092
+
1093
+ 1. **Streaming**: WebSocket es extensión, no parte del protocol estándar
1094
+ 2. **Authentication**: No definida en protocol base
1095
+ 3. **Batch operations**: No soportadas en protocol estándar
1096
+ 4. **Cancellation**: Task cancellation es custom extension
1097
+
1098
+ ---
1099
+
1100
+ ## Testing
1101
+
1102
+ ```bash
1103
+ # Test agent info
1104
+ curl http://localhost:8080/api/v1/agent
1105
+
1106
+ # Create task
1107
+ curl -X POST http://localhost:8080/api/v1/tasks \
1108
+ -H "Content-Type: application/json" \
1109
+ -d '{"input": "Build a login page"}'
1110
+
1111
+ # Execute steps until completion
1112
+ curl -X POST http://localhost:8080/api/v1/tasks/{taskId}/steps
1113
+
1114
+ # List artifacts
1115
+ curl http://localhost:8080/api/v1/tasks/{taskId}/artifacts
1116
+ ```
1117
+
1118
+ ---
1119
+
1120
+ ## Changelog
1121
+
1122
+ - **v3.2.0**: Initial Agent Protocol implementation
1123
+ - Full OpenAPI 3.1 spec
1124
+ - Task/Step/Artifact CRUD
1125
+ - WebSocket streaming extension
1126
+ - Integration with ELSABRO core systems