@olane/o-lane 0.8.1 → 0.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +185 -99
- package/dist/src/capabilities-execute/execute.capability.d.ts +1 -0
- package/dist/src/capabilities-execute/execute.capability.d.ts.map +1 -1
- package/dist/src/capabilities-execute/execute.capability.js +21 -10
- package/dist/src/capabilities-execute/interfaces/o-capability.configure-config.d.ts +4 -0
- package/dist/src/capabilities-execute/interfaces/o-capability.configure-config.d.ts.map +1 -1
- package/dist/test/execute-capability-address.spec.d.ts +2 -0
- package/dist/test/execute-capability-address.spec.d.ts.map +1 -0
- package/dist/test/execute-capability-address.spec.js +115 -0
- package/package.json +9 -9
package/README.md
CHANGED
|
@@ -14,12 +14,12 @@ The execution layer that manages AI agent processes through capability-based loo
|
|
|
14
14
|
- 📊 **Execution Tracking** - Complete sequence history with cycle-by-cycle audit trails
|
|
15
15
|
- 🌊 **Streaming Support** - Real-time progress updates to calling agents
|
|
16
16
|
- 💾 **Persistent State** - Content-addressed storage of lane execution history
|
|
17
|
-
- 🎯 **Pre-built Capabilities** - Evaluate
|
|
17
|
+
- 🎯 **Pre-built Capabilities** - Evaluate and Execute included, with Search, Configure, and Multiple Step planned
|
|
18
18
|
|
|
19
19
|
## Installation
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
|
|
22
|
+
pnpm install @olane/o-lane
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
## Quick Start
|
|
@@ -53,7 +53,7 @@ await agent.start();
|
|
|
53
53
|
|
|
54
54
|
```typescript
|
|
55
55
|
// Agent receives an intent and autonomously determines how to execute it
|
|
56
|
-
const response = await agent.use({
|
|
56
|
+
const response = await agent.use(agent.address, {
|
|
57
57
|
method: 'intent',
|
|
58
58
|
params: {
|
|
59
59
|
intent: 'Analyze the sales data and create a summary report',
|
|
@@ -62,15 +62,15 @@ const response = await agent.use({
|
|
|
62
62
|
}
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
-
console.log(response.result);
|
|
65
|
+
console.log(response.result.data);
|
|
66
66
|
// {
|
|
67
67
|
// result: "Analysis complete. Created summary report with key insights...",
|
|
68
68
|
// cycles: 5,
|
|
69
69
|
// sequence: [
|
|
70
70
|
// { type: 'EVALUATE', reasoning: '...' },
|
|
71
|
-
// { type: '
|
|
72
|
-
// { type: '
|
|
73
|
-
// { type: '
|
|
71
|
+
// { type: 'EXECUTE', result: '...' },
|
|
72
|
+
// { type: 'EVALUATE', result: '...' },
|
|
73
|
+
// { type: 'EXECUTE', result: '...' },
|
|
74
74
|
// { type: 'STOP', result: '...' }
|
|
75
75
|
// ]
|
|
76
76
|
// }
|
|
@@ -256,7 +256,7 @@ The heart of o-lane's emergent orchestration:
|
|
|
256
256
|
- **Maximum Cycles**: Configurable limit (default: 20) prevents infinite loops
|
|
257
257
|
- **State Accumulation**: Each cycle builds on previous results
|
|
258
258
|
- **Emergent Patterns**: Optimal workflows discovered through execution
|
|
259
|
-
- **Fault Tolerance**: Errors
|
|
259
|
+
- **Fault Tolerance**: Errors are handled within capability execution
|
|
260
260
|
|
|
261
261
|
```typescript
|
|
262
262
|
// The loop runs automatically in lane.execute()
|
|
@@ -289,13 +289,13 @@ console.log(lane.sequence);
|
|
|
289
289
|
// id: 'cap-1',
|
|
290
290
|
// type: 'EVALUATE',
|
|
291
291
|
// config: { intent: '...', context: '...' },
|
|
292
|
-
// result: { reasoning: 'Need to
|
|
292
|
+
// result: { reasoning: 'Need to fetch customer data', next: 'EXECUTE' }
|
|
293
293
|
// },
|
|
294
294
|
// {
|
|
295
295
|
// id: 'cap-2',
|
|
296
|
-
// type: '
|
|
297
|
-
// config: {
|
|
298
|
-
// result: { data: [...], next: '
|
|
296
|
+
// type: 'EXECUTE',
|
|
297
|
+
// config: { task: { address: 'o://data', method: 'get_customer' } },
|
|
298
|
+
// result: { data: [...], next: 'EVALUATE' }
|
|
299
299
|
// },
|
|
300
300
|
// // ... more cycles
|
|
301
301
|
// ]
|
|
@@ -312,13 +312,15 @@ console.log(lane.agentHistory);
|
|
|
312
312
|
|
|
313
313
|
## Built-in Capabilities
|
|
314
314
|
|
|
315
|
-
o-lane includes
|
|
315
|
+
o-lane includes two active capabilities, with three additional ones planned:
|
|
316
|
+
|
|
317
|
+
### Active Capabilities
|
|
316
318
|
|
|
317
319
|
### 1. Evaluate (`EVALUATE`)
|
|
318
320
|
|
|
319
321
|
**Purpose**: Analyze the intent and determine the next capability to use.
|
|
320
322
|
|
|
321
|
-
**When Used**:
|
|
323
|
+
**When Used**:
|
|
322
324
|
- Start of every lane
|
|
323
325
|
- After completing any other capability
|
|
324
326
|
- When agent needs to reassess approach
|
|
@@ -327,18 +329,20 @@ o-lane includes six core capabilities that handle most agentic workflows:
|
|
|
327
329
|
import { oCapabilityEvaluate } from '@olane/o-lane';
|
|
328
330
|
|
|
329
331
|
// Automatically uses AI to evaluate intent and choose next step
|
|
330
|
-
// Returns: { type: '
|
|
332
|
+
// Returns: { type: 'EXECUTE' | 'STOP', reasoning: '...' }
|
|
331
333
|
```
|
|
332
334
|
|
|
333
|
-
### 2.
|
|
335
|
+
### 2. Execute (`EXECUTE`)
|
|
334
336
|
|
|
335
|
-
**Purpose**: Execute a specific tool method with parameters.
|
|
337
|
+
**Purpose**: Execute a specific tool method with parameters determined by the AI agent.
|
|
336
338
|
|
|
337
339
|
**When Used**: Agent needs to call a tool (API, database, computation, etc.)
|
|
338
340
|
|
|
339
341
|
```typescript
|
|
340
|
-
|
|
341
|
-
|
|
342
|
+
import { oCapabilityExecute } from '@olane/o-lane';
|
|
343
|
+
|
|
344
|
+
// Agent decides to execute a tool call
|
|
345
|
+
// Result: { type: 'EXECUTE', config: { task: { address: 'o://tool', payload: {...} } } }
|
|
342
346
|
|
|
343
347
|
// Capability executes:
|
|
344
348
|
const response = await this.node.use(new oAddress('o://analytics'), {
|
|
@@ -347,7 +351,9 @@ const response = await this.node.use(new oAddress('o://analytics'), {
|
|
|
347
351
|
});
|
|
348
352
|
```
|
|
349
353
|
|
|
350
|
-
###
|
|
354
|
+
### Planned Capabilities (not yet active)
|
|
355
|
+
|
|
356
|
+
### 3. Search (`SEARCH`) *(planned)*
|
|
351
357
|
|
|
352
358
|
**Purpose**: Query vector stores, registries, or knowledge bases for information.
|
|
353
359
|
|
|
@@ -358,7 +364,7 @@ const response = await this.node.use(new oAddress('o://analytics'), {
|
|
|
358
364
|
// Can query vector stores, registries, or other search services
|
|
359
365
|
```
|
|
360
366
|
|
|
361
|
-
### 4. Configure (`CONFIGURE`)
|
|
367
|
+
### 4. Configure (`CONFIGURE`) *(planned)*
|
|
362
368
|
|
|
363
369
|
**Purpose**: Set up tool parameters, establish connections, or prepare environment.
|
|
364
370
|
|
|
@@ -369,19 +375,7 @@ const response = await this.node.use(new oAddress('o://analytics'), {
|
|
|
369
375
|
// Returns configuration result and proceeds to next capability
|
|
370
376
|
```
|
|
371
377
|
|
|
372
|
-
### 5.
|
|
373
|
-
|
|
374
|
-
**Purpose**: Handle errors gracefully and attempt recovery.
|
|
375
|
-
|
|
376
|
-
**When Used**: Any capability encounters an error
|
|
377
|
-
|
|
378
|
-
```typescript
|
|
379
|
-
// Automatically triggered on errors
|
|
380
|
-
// Analyzes error, determines recovery strategy
|
|
381
|
-
// Can retry, use alternative approach, or escalate
|
|
382
|
-
```
|
|
383
|
-
|
|
384
|
-
### 6. Multiple Step (`MULTIPLE_STEP`)
|
|
378
|
+
### 5. Multiple Step (`MULTIPLE_STEP`) *(planned)*
|
|
385
379
|
|
|
386
380
|
**Purpose**: Coordinate complex multi-step operations.
|
|
387
381
|
|
|
@@ -398,25 +392,21 @@ const response = await this.node.use(new oAddress('o://analytics'), {
|
|
|
398
392
|
```
|
|
399
393
|
Intent: "Analyze Q4 sales and create report"
|
|
400
394
|
↓
|
|
401
|
-
Cycle 1: EVALUATE → "Need to
|
|
402
|
-
↓
|
|
403
|
-
Cycle 2: SEARCH → Found 'o://analytics/sales'
|
|
395
|
+
Cycle 1: EVALUATE → "Need to fetch sales data"
|
|
404
396
|
↓
|
|
405
|
-
Cycle
|
|
397
|
+
Cycle 2: EXECUTE → Execute o://analytics/sales/fetch_q4_data
|
|
406
398
|
↓
|
|
407
|
-
Cycle
|
|
399
|
+
Cycle 3: EVALUATE → "Have data, need to analyze"
|
|
408
400
|
↓
|
|
409
|
-
Cycle
|
|
401
|
+
Cycle 4: EXECUTE → Execute o://analytics/analyze
|
|
410
402
|
↓
|
|
411
|
-
Cycle
|
|
403
|
+
Cycle 5: EVALUATE → "Analysis complete, create report"
|
|
412
404
|
↓
|
|
413
|
-
Cycle
|
|
405
|
+
Cycle 6: EXECUTE → Execute o://reports/create
|
|
414
406
|
↓
|
|
415
|
-
Cycle
|
|
407
|
+
Cycle 7: EVALUATE → "Report created, done"
|
|
416
408
|
↓
|
|
417
|
-
Cycle
|
|
418
|
-
↓
|
|
419
|
-
Cycle 10: STOP → Return final result
|
|
409
|
+
Cycle 8: STOP → Return final result
|
|
420
410
|
```
|
|
421
411
|
|
|
422
412
|
## API Reference
|
|
@@ -434,12 +424,20 @@ new oLane(config: oLaneConfig)
|
|
|
434
424
|
**Config Properties:**
|
|
435
425
|
- `intent: oIntent` - The intent to resolve (required)
|
|
436
426
|
- `caller: oAddress` - Address of the calling agent (required)
|
|
437
|
-
- `currentNode:
|
|
427
|
+
- `currentNode: oToolBase` - The tool executing the lane (required)
|
|
428
|
+
- `promptLoader: PromptLoader` - Prompt loader for capability prompts (required)
|
|
438
429
|
- `context?: oLaneContext` - Historical or domain context
|
|
430
|
+
- `chatHistory?: string` - Chat history string for context
|
|
439
431
|
- `streamTo?: oAddress` - Address to stream progress updates
|
|
440
|
-
- `capabilities?: oCapability[]` - Custom capability set
|
|
432
|
+
- `capabilities?: oCapability[]` - Custom capability set (overrides `enabledCapabilityTypes`)
|
|
433
|
+
- `enabledCapabilityTypes?: oCapabilityType[]` - Filter which capability types to enable from `ALL_CAPABILITIES`
|
|
434
|
+
- `extraInstructions?: string` - Additional instructions for the AI agent
|
|
441
435
|
- `maxCycles?: number` - Override default max cycles (20)
|
|
442
436
|
- `parentLaneId?: string` - Parent lane for sub-lanes
|
|
437
|
+
- `persistToConfig?: boolean` - Persist lane for replay on startup
|
|
438
|
+
- `useStream?: boolean` - Enable streaming mode
|
|
439
|
+
- `onChunk?: (chunk: any) => void` - Callback for streaming chunks
|
|
440
|
+
- `requestId?: string | number` - Request ID for request/response correlation
|
|
443
441
|
|
|
444
442
|
#### Properties
|
|
445
443
|
|
|
@@ -447,9 +445,11 @@ new oLane(config: oLaneConfig)
|
|
|
447
445
|
- `sequence: oCapabilityResult[]` - Execution history
|
|
448
446
|
- `status: oLaneStatus` - Current lifecycle state
|
|
449
447
|
- `result: oCapabilityResult` - Final execution result
|
|
450
|
-
- `id: string` - Unique lane identifier
|
|
448
|
+
- `id: string` - Unique lane identifier (UUID)
|
|
451
449
|
- `cid?: CID` - Content identifier for storage
|
|
452
450
|
- `agentHistory: string` - Formatted execution history
|
|
451
|
+
- `MAX_CYCLES: number` - Maximum capability loop iterations (default: 20)
|
|
452
|
+
- `onChunk?: (chunk: any) => void` - Streaming chunk callback
|
|
453
453
|
|
|
454
454
|
#### Methods
|
|
455
455
|
|
|
@@ -471,7 +471,7 @@ Internal capability loop execution (called by execute).
|
|
|
471
471
|
Add a capability result to the execution sequence.
|
|
472
472
|
|
|
473
473
|
```typescript
|
|
474
|
-
lane.addSequence(new oCapabilityResult({ type:
|
|
474
|
+
lane.addSequence(new oCapabilityResult({ type: oCapabilityType.EXECUTE, result: data }));
|
|
475
475
|
```
|
|
476
476
|
|
|
477
477
|
**`async store(): Promise<void>`**
|
|
@@ -492,6 +492,23 @@ const cid = await lane.toCID();
|
|
|
492
492
|
console.log(cid.toString()); // "bafyreib..."
|
|
493
493
|
```
|
|
494
494
|
|
|
495
|
+
**`getExecutionTrace(): string`**
|
|
496
|
+
|
|
497
|
+
Get a formatted trace of the lane execution for debugging.
|
|
498
|
+
|
|
499
|
+
```typescript
|
|
500
|
+
const trace = lane.getExecutionTrace();
|
|
501
|
+
console.log(trace);
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
**`async replay(cid: string): Promise<oCapabilityResult | undefined>`**
|
|
505
|
+
|
|
506
|
+
Replay a previously stored lane execution from its CID.
|
|
507
|
+
|
|
508
|
+
```typescript
|
|
509
|
+
const result = await lane.replay('bafyreib...');
|
|
510
|
+
```
|
|
511
|
+
|
|
495
512
|
**`cancel(): void`**
|
|
496
513
|
|
|
497
514
|
Cancel lane execution.
|
|
@@ -505,7 +522,15 @@ console.log(lane.status); // CANCELLED
|
|
|
505
522
|
|
|
506
523
|
### `oLaneTool` Class
|
|
507
524
|
|
|
508
|
-
Extends `oNodeTool` with lane execution capabilities
|
|
525
|
+
Extends `oNodeTool` with lane execution capabilities via the `withLane` mixin pattern:
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
// oLaneTool is defined as:
|
|
529
|
+
export class oLaneTool extends withLane(oNodeTool) { }
|
|
530
|
+
|
|
531
|
+
// The withLane mixin can be applied to any tool base class:
|
|
532
|
+
// class MyCustomLaneTool extends withLane(MyBaseClass) { }
|
|
533
|
+
```
|
|
509
534
|
|
|
510
535
|
#### Built-in Methods
|
|
511
536
|
|
|
@@ -514,7 +539,7 @@ Extends `oNodeTool` with lane execution capabilities.
|
|
|
514
539
|
Perform capability negotiation with other agents.
|
|
515
540
|
|
|
516
541
|
```typescript
|
|
517
|
-
const result = await agent.use({
|
|
542
|
+
const result = await agent.use(agent.address, {
|
|
518
543
|
method: 'handshake',
|
|
519
544
|
params: { intent: 'Discover capabilities' }
|
|
520
545
|
});
|
|
@@ -526,7 +551,7 @@ const result = await agent.use({
|
|
|
526
551
|
Main entry point for intent resolution.
|
|
527
552
|
|
|
528
553
|
```typescript
|
|
529
|
-
const result = await agent.use({
|
|
554
|
+
const result = await agent.use(agent.address, {
|
|
530
555
|
method: 'intent',
|
|
531
556
|
params: {
|
|
532
557
|
intent: 'Your natural language goal here',
|
|
@@ -536,6 +561,22 @@ const result = await agent.use({
|
|
|
536
561
|
});
|
|
537
562
|
```
|
|
538
563
|
|
|
564
|
+
**`async _tool_replay(request: oRequest): Promise<any>`**
|
|
565
|
+
|
|
566
|
+
Replay a stored lane execution from its CID.
|
|
567
|
+
|
|
568
|
+
```typescript
|
|
569
|
+
const result = await agent.use(agent.address, {
|
|
570
|
+
method: 'replay',
|
|
571
|
+
params: { cid: 'bafyreib...' }
|
|
572
|
+
});
|
|
573
|
+
// Returns: { result, error, cycles, cid }
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
#### Customization
|
|
577
|
+
|
|
578
|
+
Override `getPromptLoader()` to provide a custom `PromptLoader` for controlling how prompts are loaded for each capability type.
|
|
579
|
+
|
|
539
580
|
#### Usage Example
|
|
540
581
|
|
|
541
582
|
```typescript
|
|
@@ -550,7 +591,7 @@ class CustomAgent extends oLaneTool {
|
|
|
550
591
|
// Add domain-specific tool methods
|
|
551
592
|
async _tool_domain_action(request: oRequest): Promise<any> {
|
|
552
593
|
// Your custom logic
|
|
553
|
-
return {
|
|
594
|
+
return { result: 'done' };
|
|
554
595
|
}
|
|
555
596
|
}
|
|
556
597
|
```
|
|
@@ -619,12 +660,32 @@ const manager = new oLaneManager();
|
|
|
619
660
|
const lane = await manager.createLane({
|
|
620
661
|
intent: new oIntent({ intent: 'Your goal' }),
|
|
621
662
|
currentNode: agentTool,
|
|
622
|
-
caller: callerAddress
|
|
663
|
+
caller: callerAddress,
|
|
664
|
+
promptLoader: myPromptLoader
|
|
623
665
|
});
|
|
624
666
|
|
|
625
667
|
// Lane is automatically tracked
|
|
626
668
|
```
|
|
627
669
|
|
|
670
|
+
#### Properties
|
|
671
|
+
|
|
672
|
+
- `lanes: oLane[]` - All tracked lanes
|
|
673
|
+
- `activeLanes: oLane[]` - Currently running lanes
|
|
674
|
+
- `staleLanes: oLane[]` - Lanes that are no longer active
|
|
675
|
+
- `maxLanes: number` - Maximum concurrent lanes (default: 100)
|
|
676
|
+
|
|
677
|
+
#### Methods
|
|
678
|
+
|
|
679
|
+
**`async createLane(config: oLaneConfig): Promise<oLane>`** - Create and track a new lane.
|
|
680
|
+
|
|
681
|
+
**`getLane(id: string): oLane | undefined`** - Retrieve a lane by its ID.
|
|
682
|
+
|
|
683
|
+
**`cancelLane(lane: oLane): void`** - Cancel a running lane.
|
|
684
|
+
|
|
685
|
+
**`cleanLanes(): void`** - Remove completed/stale lanes from tracking.
|
|
686
|
+
|
|
687
|
+
**`async teardown(): Promise<void>`** - Cancel all active lanes and clean up.
|
|
688
|
+
|
|
628
689
|
---
|
|
629
690
|
|
|
630
691
|
### `oCapabilityResult` Class
|
|
@@ -643,10 +704,12 @@ const result = new oCapabilityResult({
|
|
|
643
704
|
```
|
|
644
705
|
|
|
645
706
|
**Properties:**
|
|
707
|
+
- `id: string` - Unique result identifier
|
|
646
708
|
- `type: oCapabilityType` - Next capability to execute
|
|
647
|
-
- `result
|
|
648
|
-
- `config?:
|
|
709
|
+
- `result?: any` - Execution result data
|
|
710
|
+
- `config?: oCapabilityConfig` - Configuration for next capability
|
|
649
711
|
- `error?: string` - Error message if failed
|
|
712
|
+
- `shouldPersist?: boolean` - Whether this result should be persisted to storage
|
|
650
713
|
|
|
651
714
|
---
|
|
652
715
|
|
|
@@ -670,14 +733,14 @@ enum oLaneStatus {
|
|
|
670
733
|
|
|
671
734
|
```typescript
|
|
672
735
|
enum oCapabilityType {
|
|
673
|
-
EVALUATE = 'evaluate',
|
|
674
736
|
TASK = 'task',
|
|
675
737
|
SEARCH = 'search',
|
|
676
|
-
CONFIGURE = 'configure',
|
|
677
|
-
ERROR = 'error',
|
|
678
738
|
MULTIPLE_STEP = 'multiple_step',
|
|
739
|
+
CONFIGURE = 'configure',
|
|
740
|
+
EXECUTE = 'execute',
|
|
741
|
+
HANDSHAKE = 'handshake',
|
|
742
|
+
EVALUATE = 'evaluate',
|
|
679
743
|
STOP = 'stop',
|
|
680
|
-
RESULT = 'result',
|
|
681
744
|
UNKNOWN = 'unknown'
|
|
682
745
|
}
|
|
683
746
|
```
|
|
@@ -699,17 +762,17 @@ const agent = new oLaneTool({
|
|
|
699
762
|
await agent.start();
|
|
700
763
|
|
|
701
764
|
// Resolve an intent
|
|
702
|
-
const response = await agent.use({
|
|
765
|
+
const response = await agent.use(agent.address, {
|
|
703
766
|
method: 'intent',
|
|
704
767
|
params: {
|
|
705
768
|
intent: 'Find the latest sales report and summarize key metrics'
|
|
706
769
|
}
|
|
707
770
|
});
|
|
708
771
|
|
|
709
|
-
console.log('Result:', response.result);
|
|
710
|
-
console.log('Cycles used:', response.cycles);
|
|
711
|
-
console.log('Execution path:', response.sequence.map(s => s.type));
|
|
712
|
-
// ['EVALUATE', '
|
|
772
|
+
console.log('Result:', response.result.data);
|
|
773
|
+
console.log('Cycles used:', response.result.data.cycles);
|
|
774
|
+
console.log('Execution path:', response.result.data.sequence.map(s => s.type));
|
|
775
|
+
// ['EVALUATE', 'EXECUTE', 'EVALUATE', 'EXECUTE', 'STOP']
|
|
713
776
|
```
|
|
714
777
|
|
|
715
778
|
### Custom Capability
|
|
@@ -741,9 +804,9 @@ class EmailCapability extends oCapability {
|
|
|
741
804
|
});
|
|
742
805
|
} catch (error) {
|
|
743
806
|
return new oCapabilityResult({
|
|
744
|
-
type: oCapabilityType.
|
|
807
|
+
type: oCapabilityType.EVALUATE,
|
|
745
808
|
error: error.message,
|
|
746
|
-
config: { intent: this.intent
|
|
809
|
+
config: { intent: this.intent }
|
|
747
810
|
});
|
|
748
811
|
}
|
|
749
812
|
}
|
|
@@ -758,10 +821,11 @@ const lane = await manager.createLane({
|
|
|
758
821
|
intent: new oIntent({ intent: 'Send status update to team' }),
|
|
759
822
|
currentNode: agentTool,
|
|
760
823
|
caller: callerAddress,
|
|
824
|
+
promptLoader: myPromptLoader,
|
|
761
825
|
capabilities: [
|
|
762
826
|
new oCapabilityEvaluate(),
|
|
763
|
-
new
|
|
764
|
-
new
|
|
827
|
+
new oCapabilityExecute(),
|
|
828
|
+
new EmailCapability()
|
|
765
829
|
]
|
|
766
830
|
});
|
|
767
831
|
|
|
@@ -787,7 +851,7 @@ const receiver = new StreamReceiver({
|
|
|
787
851
|
await receiver.start();
|
|
788
852
|
|
|
789
853
|
// Execute intent with streaming
|
|
790
|
-
const response = await agent.use({
|
|
854
|
+
const response = await agent.use(agent.address, {
|
|
791
855
|
method: 'intent',
|
|
792
856
|
params: {
|
|
793
857
|
intent: 'Process large dataset',
|
|
@@ -807,8 +871,10 @@ const response = await agent.use({
|
|
|
807
871
|
```typescript
|
|
808
872
|
import { oLaneContext } from '@olane/o-lane';
|
|
809
873
|
|
|
810
|
-
//
|
|
811
|
-
const context = new oLaneContext(
|
|
874
|
+
// Create context and add entries
|
|
875
|
+
const context = new oLaneContext({});
|
|
876
|
+
|
|
877
|
+
context.addAll([
|
|
812
878
|
'[Previous Conversation]',
|
|
813
879
|
'User: What were our sales last quarter?',
|
|
814
880
|
'Agent: Q3 sales were $1.2M, up 15% from Q2.',
|
|
@@ -816,7 +882,10 @@ const context = new oLaneContext([
|
|
|
816
882
|
'[End Previous Conversation]'
|
|
817
883
|
]);
|
|
818
884
|
|
|
819
|
-
|
|
885
|
+
// Or add individual entries
|
|
886
|
+
context.add('Additional context here');
|
|
887
|
+
|
|
888
|
+
const response = await agent.use(agent.address, {
|
|
820
889
|
method: 'intent',
|
|
821
890
|
params: {
|
|
822
891
|
intent: 'Calculate Q4 projections',
|
|
@@ -831,7 +900,7 @@ const response = await agent.use({
|
|
|
831
900
|
|
|
832
901
|
```typescript
|
|
833
902
|
// Complex intent requiring multiple capabilities
|
|
834
|
-
const response = await agent.use({
|
|
903
|
+
const response = await agent.use(agent.address, {
|
|
835
904
|
method: 'intent',
|
|
836
905
|
params: {
|
|
837
906
|
intent: 'Analyze customer feedback from last month, identify common themes, and create action items'
|
|
@@ -839,8 +908,9 @@ const response = await agent.use({
|
|
|
839
908
|
});
|
|
840
909
|
|
|
841
910
|
// Analyze the execution path
|
|
911
|
+
const data = response.result.data;
|
|
842
912
|
console.log('Execution Analysis:');
|
|
843
|
-
|
|
913
|
+
data.sequence.forEach((step, index) => {
|
|
844
914
|
console.log(`\nCycle ${index + 1}:`);
|
|
845
915
|
console.log(` Type: ${step.type}`);
|
|
846
916
|
console.log(` Reasoning: ${step.reasoning}`);
|
|
@@ -850,15 +920,15 @@ response.sequence.forEach((step, index) => {
|
|
|
850
920
|
});
|
|
851
921
|
|
|
852
922
|
// Output might show:
|
|
853
|
-
// Cycle 1: EVALUATE - "Need to
|
|
854
|
-
// Cycle 2:
|
|
855
|
-
// Cycle 3:
|
|
856
|
-
// Cycle 4:
|
|
857
|
-
// Cycle 5:
|
|
858
|
-
// Cycle 6:
|
|
859
|
-
// Cycle 7:
|
|
860
|
-
// Cycle 8:
|
|
861
|
-
// Cycle 9:
|
|
923
|
+
// Cycle 1: EVALUATE - "Need to fetch feedback data"
|
|
924
|
+
// Cycle 2: EXECUTE - Fetched 145 feedback items from o://feedback/collector
|
|
925
|
+
// Cycle 3: EVALUATE - "Have data, need sentiment analysis"
|
|
926
|
+
// Cycle 4: EXECUTE - Analyzed sentiment across feedback
|
|
927
|
+
// Cycle 5: EVALUATE - "Need to identify themes"
|
|
928
|
+
// Cycle 6: EXECUTE - Extracted 5 common themes
|
|
929
|
+
// Cycle 7: EVALUATE - "Ready to create action items"
|
|
930
|
+
// Cycle 8: EXECUTE - Generated 8 action items
|
|
931
|
+
// Cycle 9: EVALUATE - "All tasks complete"
|
|
862
932
|
// Cycle 10: STOP - Completed successfully
|
|
863
933
|
```
|
|
864
934
|
|
|
@@ -902,7 +972,7 @@ class DatabaseQueryCapability extends oCapability {
|
|
|
902
972
|
});
|
|
903
973
|
} catch (error) {
|
|
904
974
|
return new oCapabilityResult({
|
|
905
|
-
type: oCapabilityType.
|
|
975
|
+
type: oCapabilityType.EVALUATE,
|
|
906
976
|
error: error.message
|
|
907
977
|
});
|
|
908
978
|
}
|
|
@@ -920,6 +990,20 @@ class DatabaseQueryCapability extends oCapability {
|
|
|
920
990
|
- Integration with external systems
|
|
921
991
|
- Performance-critical operations requiring optimization
|
|
922
992
|
|
|
993
|
+
### Prompt Loading
|
|
994
|
+
|
|
995
|
+
Lanes require a `PromptLoader` to load prompts for each capability type. The `PromptLoader` abstract class provides a `loadPromptForType(type, params?, provider?)` method. A `PromptLoaderDefault` implementation is included for standard use cases.
|
|
996
|
+
|
|
997
|
+
To customize prompt loading in your `oLaneTool`, override `getPromptLoader()`:
|
|
998
|
+
|
|
999
|
+
```typescript
|
|
1000
|
+
class MyAgent extends oLaneTool {
|
|
1001
|
+
getPromptLoader(): PromptLoader {
|
|
1002
|
+
return new MyCustomPromptLoader();
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
```
|
|
1006
|
+
|
|
923
1007
|
### Lane Context
|
|
924
1008
|
|
|
925
1009
|
Provide rich context to help agents make better decisions:
|
|
@@ -928,7 +1012,8 @@ Provide rich context to help agents make better decisions:
|
|
|
928
1012
|
import { oLaneContext } from '@olane/o-lane';
|
|
929
1013
|
|
|
930
1014
|
// Conversation context
|
|
931
|
-
const conversationContext = new oLaneContext(
|
|
1015
|
+
const conversationContext = new oLaneContext({});
|
|
1016
|
+
conversationContext.addAll([
|
|
932
1017
|
'[Chat History]',
|
|
933
1018
|
'User: Show me last quarter sales',
|
|
934
1019
|
'Agent: Q3 sales: $1.2M (↑15%)',
|
|
@@ -936,7 +1021,8 @@ const conversationContext = new oLaneContext([
|
|
|
936
1021
|
]);
|
|
937
1022
|
|
|
938
1023
|
// Domain knowledge context
|
|
939
|
-
const domainContext = new oLaneContext(
|
|
1024
|
+
const domainContext = new oLaneContext({});
|
|
1025
|
+
domainContext.addAll([
|
|
940
1026
|
'[Business Rules]',
|
|
941
1027
|
'- Sales reports require manager approval',
|
|
942
1028
|
'- Sensitive data must be redacted',
|
|
@@ -945,12 +1031,13 @@ const domainContext = new oLaneContext([
|
|
|
945
1031
|
]);
|
|
946
1032
|
|
|
947
1033
|
// Combine contexts
|
|
948
|
-
const combinedContext = new oLaneContext(
|
|
949
|
-
|
|
950
|
-
|
|
1034
|
+
const combinedContext = new oLaneContext({});
|
|
1035
|
+
combinedContext.addAll([
|
|
1036
|
+
conversationContext.toString(),
|
|
1037
|
+
domainContext.toString()
|
|
951
1038
|
]);
|
|
952
1039
|
|
|
953
|
-
const response = await agent.use({
|
|
1040
|
+
const response = await agent.use(agent.address, {
|
|
954
1041
|
method: 'intent',
|
|
955
1042
|
params: {
|
|
956
1043
|
intent: 'Generate Q4 sales report',
|
|
@@ -1027,7 +1114,7 @@ const tracker = new ProgressTracker({
|
|
|
1027
1114
|
await tracker.start();
|
|
1028
1115
|
|
|
1029
1116
|
// Long-running task with progress updates
|
|
1030
|
-
const response = await agent.use({
|
|
1117
|
+
const response = await agent.use(agent.address, {
|
|
1031
1118
|
method: 'intent',
|
|
1032
1119
|
params: {
|
|
1033
1120
|
intent: 'Process 10,000 customer records',
|
|
@@ -1044,7 +1131,7 @@ Access historical lane executions:
|
|
|
1044
1131
|
import { oAddress } from '@olane/o-core';
|
|
1045
1132
|
|
|
1046
1133
|
// Execute and store lane
|
|
1047
|
-
const response = await agent.use({
|
|
1134
|
+
const response = await agent.use(agent.address, {
|
|
1048
1135
|
method: 'intent',
|
|
1049
1136
|
params: { intent: 'Analyze sales data' }
|
|
1050
1137
|
});
|
|
@@ -1059,7 +1146,7 @@ const storedLane = await agent.use(new oAddress('o://lane'), {
|
|
|
1059
1146
|
params: { key: cid.toString() }
|
|
1060
1147
|
});
|
|
1061
1148
|
|
|
1062
|
-
console.log('Historical execution:', storedLane.result);
|
|
1149
|
+
console.log('Historical execution:', storedLane.result.data);
|
|
1063
1150
|
// {
|
|
1064
1151
|
// config: { intent: '...', caller: '...' },
|
|
1065
1152
|
// sequence: [...],
|
|
@@ -1419,10 +1506,9 @@ import { ALL_CAPABILITIES } from '@olane/o-lane';
|
|
|
1419
1506
|
"Do analysis" → "Calculate average sales per region for Q4 2024"
|
|
1420
1507
|
|
|
1421
1508
|
// 2. Provide context
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
])
|
|
1509
|
+
const ctx = new oLaneContext({});
|
|
1510
|
+
ctx.addAll(['Available data: sales_q4.csv', 'Required format: JSON with region, avg_sales fields']);
|
|
1511
|
+
// then pass: context: ctx
|
|
1426
1512
|
|
|
1427
1513
|
// 3. Add specialized capabilities
|
|
1428
1514
|
capabilities: [...ALL_CAPABILITIES, new DataAnalysisCapability()]
|
|
@@ -6,6 +6,7 @@ export declare class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
6
6
|
config: oCapabilityExecuteConfig;
|
|
7
7
|
get type(): oCapabilityType;
|
|
8
8
|
static get type(): oCapabilityType;
|
|
9
|
+
private resolveAddress;
|
|
9
10
|
loadPrompt({ tools, methods }: any): Promise<string>;
|
|
10
11
|
handshake(): Promise<oHandshakeResult>;
|
|
11
12
|
run(): Promise<oCapabilityResult>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"execute.capability.d.ts","sourceRoot":"","sources":["../../../src/capabilities-execute/execute.capability.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAEzF,qBAAa,kBAAmB,SAAQ,uBAAuB;IACtD,MAAM,EAAG,wBAAwB,CAAC;IAEzC,IAAI,IAAI,IAAI,eAAe,CAE1B;IAED,MAAM,KAAK,IAAI,oBAEd;
|
|
1
|
+
{"version":3,"file":"execute.capability.d.ts","sourceRoot":"","sources":["../../../src/capabilities-execute/execute.capability.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,uBAAuB,EAAE,MAAM,8CAA8C,CAAC;AAEvF,OAAO,EAAE,gBAAgB,EAAE,MAAM,mCAAmC,CAAC;AACrE,OAAO,EAAE,wBAAwB,EAAE,MAAM,+CAA+C,CAAC;AAEzF,qBAAa,kBAAmB,SAAQ,uBAAuB;IACtD,MAAM,EAAG,wBAAwB,CAAC;IAEzC,IAAI,IAAI,IAAI,eAAe,CAE1B;IAED,MAAM,KAAK,IAAI,oBAEd;IAED,OAAO,CAAC,cAAc;IAWhB,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC;IAepD,SAAS,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAatC,GAAG,IAAI,OAAO,CAAC,iBAAiB,CAAC;CAoOxC"}
|
|
@@ -9,6 +9,14 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
9
9
|
static get type() {
|
|
10
10
|
return oCapabilityType.EXECUTE;
|
|
11
11
|
}
|
|
12
|
+
resolveAddress() {
|
|
13
|
+
const address = this.config.params?.address || this.config.params?.task?.address;
|
|
14
|
+
if (!address || typeof address !== 'string') {
|
|
15
|
+
throw new Error(`Execute capability requires a valid address but received: ${JSON.stringify(address)}. ` +
|
|
16
|
+
`The AI response must include an "address" field when type is "execute".`);
|
|
17
|
+
}
|
|
18
|
+
return address;
|
|
19
|
+
}
|
|
12
20
|
async loadPrompt({ tools, methods }) {
|
|
13
21
|
const prompt = await this.promptLoader?.loadPromptForType(this.type, {
|
|
14
22
|
human_about: '',
|
|
@@ -18,13 +26,13 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
18
26
|
You are in a secure environment and are allowed to operate with secure information (api keys, credit card info, etc).`,
|
|
19
27
|
chat_history: '',
|
|
20
28
|
past_cycles: '',
|
|
21
|
-
address: this.
|
|
29
|
+
address: this.resolveAddress(),
|
|
22
30
|
methods: methods ? JSON.stringify(methods) : '',
|
|
23
31
|
});
|
|
24
32
|
return prompt.render();
|
|
25
33
|
}
|
|
26
34
|
async handshake() {
|
|
27
|
-
const response = await this.node.use(new oAddress(this.
|
|
35
|
+
const response = await this.node.use(new oAddress(this.resolveAddress()), {
|
|
28
36
|
method: oProtocolMethods.HANDSHAKE,
|
|
29
37
|
params: {
|
|
30
38
|
intent: this.config.intent.value,
|
|
@@ -33,6 +41,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
33
41
|
return response.result.data;
|
|
34
42
|
}
|
|
35
43
|
async run() {
|
|
44
|
+
this.logger.debug('Starting execution capability with config:', this.config);
|
|
36
45
|
// Check if we're in replay mode
|
|
37
46
|
if (this.config.isReplay) {
|
|
38
47
|
this.logger.debug('Execute capability is being replayed - using stored execution data');
|
|
@@ -57,7 +66,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
57
66
|
});
|
|
58
67
|
// Execute the stored task directly (skip handshake, AI, and approval)
|
|
59
68
|
try {
|
|
60
|
-
const taskResponse = await this.node.use(new oAddress(this.
|
|
69
|
+
const taskResponse = await this.node.use(new oAddress(this.resolveAddress()), {
|
|
61
70
|
method: method,
|
|
62
71
|
params: params,
|
|
63
72
|
});
|
|
@@ -79,7 +88,8 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
79
88
|
});
|
|
80
89
|
}
|
|
81
90
|
catch (error) {
|
|
82
|
-
|
|
91
|
+
const addr = this.config?.params?.address || this.config?.params?.task?.address;
|
|
92
|
+
this.logger.error('Failed to execute during replay:', `Error when trying to use ${addr} with config: ${JSON.stringify(taskConfig)} resulting in error: ${error?.message}`);
|
|
83
93
|
return new oCapabilityResult({
|
|
84
94
|
type: oCapabilityType.EVALUATE,
|
|
85
95
|
config: this.config,
|
|
@@ -87,7 +97,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
87
97
|
handshakeResult: handshakeResult,
|
|
88
98
|
taskConfig: taskConfig,
|
|
89
99
|
},
|
|
90
|
-
error: `Error when trying to use ${
|
|
100
|
+
error: `Error when trying to use ${addr} with config: ${JSON.stringify(taskConfig)} resulting in error: ${error?.message}`,
|
|
91
101
|
});
|
|
92
102
|
}
|
|
93
103
|
}
|
|
@@ -116,7 +126,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
116
126
|
const approvalResponse = await this.node.use(new oAddress('o://approval'), {
|
|
117
127
|
method: 'request_approval',
|
|
118
128
|
params: {
|
|
119
|
-
toolAddress: this.
|
|
129
|
+
toolAddress: this.resolveAddress(),
|
|
120
130
|
method: method,
|
|
121
131
|
params: params,
|
|
122
132
|
intent: this.config.intent,
|
|
@@ -142,7 +152,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
142
152
|
}
|
|
143
153
|
try {
|
|
144
154
|
// Execute the task
|
|
145
|
-
const taskResponse = await this.node.use(new oAddress(this.
|
|
155
|
+
const taskResponse = await this.node.use(new oAddress(this.resolveAddress()), {
|
|
146
156
|
method: method,
|
|
147
157
|
params: params,
|
|
148
158
|
});
|
|
@@ -164,14 +174,15 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
164
174
|
method: method,
|
|
165
175
|
params: params,
|
|
166
176
|
},
|
|
167
|
-
address: this.
|
|
177
|
+
address: this.resolveAddress(),
|
|
168
178
|
response: taskResponse.result,
|
|
169
179
|
},
|
|
170
180
|
shouldPersist,
|
|
171
181
|
});
|
|
172
182
|
}
|
|
173
183
|
catch (error) {
|
|
174
|
-
|
|
184
|
+
const addr = this.config?.params?.address || this.config?.params?.task?.address;
|
|
185
|
+
this.logger.error('Failed to execute:', `Error when trying to use ${addr} with config: ${JSON.stringify({
|
|
175
186
|
method: method,
|
|
176
187
|
params: params,
|
|
177
188
|
})} resulting in error: ${error?.message}`);
|
|
@@ -188,7 +199,7 @@ export class oCapabilityExecute extends oCapabilityIntelligence {
|
|
|
188
199
|
params: params,
|
|
189
200
|
},
|
|
190
201
|
},
|
|
191
|
-
error: `Error when trying to use ${
|
|
202
|
+
error: `Error when trying to use ${addr} with config: ${JSON.stringify({
|
|
192
203
|
method: method,
|
|
193
204
|
params: params,
|
|
194
205
|
})} resulting in error: ${error?.message}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"o-capability.configure-config.d.ts","sourceRoot":"","sources":["../../../../src/capabilities-execute/interfaces/o-capability.configure-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE;YACf,KAAK,EAAE,MAAM,EAAE,CAAC;YAChB,OAAO,EAAE;gBAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;aAAE,CAAC;SACrC,CAAC;QACF,UAAU,EAAE;YACV,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,GAAG,CAAC;SACb,CAAC;KACH,CAAC;CACH"}
|
|
1
|
+
{"version":3,"file":"o-capability.configure-config.d.ts","sourceRoot":"","sources":["../../../../src/capabilities-execute/interfaces/o-capability.configure-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,2CAA2C,CAAC;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAE5C,MAAM,WAAW,wBAAyB,SAAQ,iBAAiB;IACjE,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,eAAe,EAAE;YACf,KAAK,EAAE,MAAM,EAAE,CAAC;YAChB,OAAO,EAAE;gBAAE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;aAAE,CAAC;SACrC,CAAC;QACF,UAAU,EAAE;YACV,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,EAAE,GAAG,CAAC;SACb,CAAC;QACF,IAAI,CAAC,EAAE;YACL,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;KACH,CAAC;CACH"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"execute-capability-address.spec.d.ts","sourceRoot":"","sources":["../../test/execute-capability-address.spec.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { expect } from 'chai';
|
|
2
|
+
import { oCapabilityConfig } from '../src/capabilities/o-capability.config.js';
|
|
3
|
+
import { oCapabilityExecute } from '../src/capabilities-execute/execute.capability.js';
|
|
4
|
+
import { oIntent } from '../src/intent/o-intent.js';
|
|
5
|
+
/**
|
|
6
|
+
* Tests the interface contract between EVALUATE results and the EXECUTE capability.
|
|
7
|
+
*
|
|
8
|
+
* When EVALUATE's AI returns type:"execute", the response may place the address
|
|
9
|
+
* either at the root level or nested inside a `task` object. resultToConfig()
|
|
10
|
+
* passes the AI result as `params`, so the execute capability must handle both shapes.
|
|
11
|
+
*/
|
|
12
|
+
describe('EVALUATE → EXECUTE handoff: address resolution', () => {
|
|
13
|
+
// Minimal stub that satisfies oToolBase enough for oCapabilityConfig
|
|
14
|
+
const stubNode = {};
|
|
15
|
+
const stubPromptLoader = {};
|
|
16
|
+
const intent = new oIntent({ intent: 'test intent' });
|
|
17
|
+
/**
|
|
18
|
+
* Simulates what resultToConfig() does: it takes the AI result object
|
|
19
|
+
* and sets it as `params` on the next capability's config.
|
|
20
|
+
*/
|
|
21
|
+
function simulateResultToConfig(aiResult) {
|
|
22
|
+
const obj = aiResult;
|
|
23
|
+
return oCapabilityConfig.fromJSON({
|
|
24
|
+
params: typeof obj === 'object' ? obj : {},
|
|
25
|
+
intent,
|
|
26
|
+
node: stubNode,
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Creates an oCapabilityExecute instance and sets its config,
|
|
31
|
+
* then calls the private resolveAddress() via the prototype.
|
|
32
|
+
*/
|
|
33
|
+
function resolveAddressFrom(config) {
|
|
34
|
+
const capability = new oCapabilityExecute({
|
|
35
|
+
promptLoader: stubPromptLoader,
|
|
36
|
+
node: stubNode,
|
|
37
|
+
});
|
|
38
|
+
// Set config as execute() would
|
|
39
|
+
capability.config = config;
|
|
40
|
+
// Call private method
|
|
41
|
+
return capability.resolveAddress();
|
|
42
|
+
}
|
|
43
|
+
describe('resolveAddress()', () => {
|
|
44
|
+
it('should resolve address from params.address (flat AI response)', () => {
|
|
45
|
+
const aiResult = {
|
|
46
|
+
type: 'execute',
|
|
47
|
+
address: 'o://search',
|
|
48
|
+
summary: 'Searching for something',
|
|
49
|
+
reasoning: 'User wants to search',
|
|
50
|
+
};
|
|
51
|
+
const config = simulateResultToConfig(aiResult);
|
|
52
|
+
const address = resolveAddressFrom(config);
|
|
53
|
+
expect(address).to.equal('o://search');
|
|
54
|
+
});
|
|
55
|
+
it('should resolve address from params.task.address (nested AI response)', () => {
|
|
56
|
+
const aiResult = {
|
|
57
|
+
type: 'execute',
|
|
58
|
+
task: {
|
|
59
|
+
address: 'o://search',
|
|
60
|
+
intent: 'Search for card feed refresh functionality',
|
|
61
|
+
},
|
|
62
|
+
summary: 'Searching for card feed refresh functionality',
|
|
63
|
+
reasoning: 'The intent mentions refreshing',
|
|
64
|
+
};
|
|
65
|
+
const config = simulateResultToConfig(aiResult);
|
|
66
|
+
const address = resolveAddressFrom(config);
|
|
67
|
+
expect(address).to.equal('o://search');
|
|
68
|
+
});
|
|
69
|
+
it('should prefer params.address over params.task.address when both exist', () => {
|
|
70
|
+
const aiResult = {
|
|
71
|
+
type: 'execute',
|
|
72
|
+
address: 'o://primary',
|
|
73
|
+
task: {
|
|
74
|
+
address: 'o://fallback',
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
const config = simulateResultToConfig(aiResult);
|
|
78
|
+
const address = resolveAddressFrom(config);
|
|
79
|
+
expect(address).to.equal('o://primary');
|
|
80
|
+
});
|
|
81
|
+
it('should throw when neither address location is present', () => {
|
|
82
|
+
const aiResult = {
|
|
83
|
+
type: 'execute',
|
|
84
|
+
summary: 'Missing address entirely',
|
|
85
|
+
reasoning: 'Bad AI response',
|
|
86
|
+
};
|
|
87
|
+
const config = simulateResultToConfig(aiResult);
|
|
88
|
+
expect(() => resolveAddressFrom(config)).to.throw('Execute capability requires a valid address');
|
|
89
|
+
});
|
|
90
|
+
it('should throw when address is not a string', () => {
|
|
91
|
+
const aiResult = {
|
|
92
|
+
type: 'execute',
|
|
93
|
+
address: 123,
|
|
94
|
+
};
|
|
95
|
+
const config = simulateResultToConfig(aiResult);
|
|
96
|
+
expect(() => resolveAddressFrom(config)).to.throw('Execute capability requires a valid address');
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
describe('resultToConfig() params shape', () => {
|
|
100
|
+
it('should pass AI result object as params', () => {
|
|
101
|
+
const aiResult = {
|
|
102
|
+
type: 'execute',
|
|
103
|
+
address: 'o://search',
|
|
104
|
+
task: { address: 'o://search', intent: 'find things' },
|
|
105
|
+
summary: 'test',
|
|
106
|
+
};
|
|
107
|
+
const config = simulateResultToConfig(aiResult);
|
|
108
|
+
expect(config.params).to.deep.equal(aiResult);
|
|
109
|
+
});
|
|
110
|
+
it('should set params to empty object for non-object results', () => {
|
|
111
|
+
const config = simulateResultToConfig('not an object');
|
|
112
|
+
expect(config.params).to.deep.equal({});
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@olane/o-lane",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/src/index.js",
|
|
6
6
|
"types": "dist/src/index.d.ts",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@eslint/eslintrc": "^3.3.1",
|
|
38
38
|
"@eslint/js": "^9.29.0",
|
|
39
|
-
"@olane/o-test": "0.8.
|
|
39
|
+
"@olane/o-test": "0.8.3",
|
|
40
40
|
"@tsconfig/node20": "^20.1.6",
|
|
41
41
|
"@types/handlebars": "^4.1.0",
|
|
42
42
|
"@types/jest": "^30.0.0",
|
|
@@ -57,15 +57,15 @@
|
|
|
57
57
|
"typescript": "5.4.5"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@olane/o-config": "0.8.
|
|
61
|
-
"@olane/o-core": "0.8.
|
|
62
|
-
"@olane/o-node": "0.8.
|
|
63
|
-
"@olane/o-protocol": "0.8.
|
|
64
|
-
"@olane/o-storage": "0.8.
|
|
65
|
-
"@olane/o-tool": "0.8.
|
|
60
|
+
"@olane/o-config": "0.8.3",
|
|
61
|
+
"@olane/o-core": "0.8.3",
|
|
62
|
+
"@olane/o-node": "0.8.3",
|
|
63
|
+
"@olane/o-protocol": "0.8.3",
|
|
64
|
+
"@olane/o-storage": "0.8.3",
|
|
65
|
+
"@olane/o-tool": "0.8.3",
|
|
66
66
|
"debug": "^4.4.1",
|
|
67
67
|
"dotenv": "^16.5.0",
|
|
68
68
|
"handlebars": "^4.7.8"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "189c0cf7b6dd9d5d961f5424af21d37978092d9e"
|
|
71
71
|
}
|