Skip to content

Commit dac0753

Browse files
Enhance OpenTelemetry documentation and update package dependencies (kaiban-ai#250)
- Expanded the README.md to include detailed span hierarchy and span kinds for better understanding of the tracing structure. - Updated event descriptions for task and agent events to reflect new statuses. - Added new attributes for tasks and agents to improve observability. - Included span context management details to clarify how spans are correlated. - Updated package-lock.json to include new dependencies and version updates for improved functionality.
2 parents 4060748 + daaf5b3 commit dac0753

File tree

4 files changed

+1334
-15
lines changed

4 files changed

+1334
-15
lines changed

packages/opentelemetry/README.md

Lines changed: 110 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -101,24 +101,90 @@ interface OpenTelemetryConfig {
101101
The package creates simplified traces with the following structure:
102102

103103
```
104-
Task Span (DOING → DONE)
105-
├── Agent Thinking Span (THINKING_END)
106-
├── Agent Thinking Span (THINKING_END)
107-
└── Agent Thinking Span (THINKING_END)
104+
Task Span (CLIENT) - DOING → DONE
105+
├── Agent Thinking Span (CLIENT) - THINKING → THINKING_END
106+
├── Agent Thinking Span (CLIENT) - THINKING → THINKING_END
107+
└── Agent Thinking Span (CLIENT) - THINKING → THINKING_END
108108
```
109109

110+
### Span Hierarchy
111+
112+
- **Task Spans**: Individual task execution spans
113+
- **Agent Thinking Spans**: Nested spans for agent LLM interactions
114+
115+
### Span Kinds
116+
117+
The package automatically determines span kinds based on span names:
118+
119+
- **CLIENT** (2): Task and Agent spans - represent client operations
120+
- **INTERNAL** (0): Default for other spans - internal operations
121+
110122
## Supported Events
111123

124+
The package processes the following KaibanJS workflow events:
125+
112126
### Task Events
113127

114-
- `task.execute` - Task execution started (DOING)
115-
- `task.complete` - Task completed successfully (DONE)
116-
- `task.error` - Task failed with error (ERRORED)
117-
- `task.abort` - Task aborted (ABORTED)
128+
- `TaskStatusUpdate` - Task execution lifecycle events
129+
- `DOING` - Task execution started
130+
- `DONE` - Task completed successfully
131+
- `AWAITING_VALIDATION` - Task awaiting validation
132+
- `VALIDATED` - Task validated successfully
133+
- `ERRORED` - Task failed with error
134+
- `ABORTED` - Task aborted
118135

119136
### Agent Events
120137

121-
- `agent.thinking` - Agent thinking span (THINKING_END)
138+
- `AgentStatusUpdate` - Agent thinking and execution events
139+
- `THINKING` - Agent begins thinking process
140+
- `THINKING_END` - Agent completes thinking process
141+
142+
## Span Context Management
143+
144+
The package uses a `KaibanSpanContext` to manage span relationships and correlation across workflows:
145+
146+
### Context Structure
147+
148+
```typescript
149+
interface KaibanSpanContext {
150+
teamName: string;
151+
workflowId: string;
152+
rootSpan?: Span;
153+
taskSpans: Map<string, Span>;
154+
agentSpans: Map<string, Span>;
155+
}
156+
```
157+
158+
### Context Methods
159+
160+
- **Root Span Management**:
161+
162+
- `setRootSpan(span: Span)` - Set the workflow root span
163+
- `getRootSpan()` - Get the current root span
164+
165+
- **Task Span Management**:
166+
167+
- `setTaskSpan(taskId: string, span: Span)` - Associate a span with a task
168+
- `getTaskSpan(taskId: string)` - Retrieve task span
169+
- `removeTaskSpan(taskId: string)` - Remove task span from context
170+
171+
- **Agent Span Management**:
172+
- `setAgentSpan(agentId: string, span: Span)` - Associate a span with an agent
173+
- `getAgentSpan(agentId: string)` - Retrieve agent span
174+
- `removeAgentSpan(agentId: string)` - Remove agent span from context
175+
176+
### Context Lifecycle
177+
178+
1. **Task Execution**: Task spans are created
179+
2. **Agent Thinking**: Agent thinking spans are nested under task spans
180+
3. **Task Completion**: All spans are completed and context is cleared
181+
182+
### Span Correlation
183+
184+
The context ensures proper parent-child relationships between spans:
185+
186+
- Task spans are parents of agent thinking spans
187+
- All spans maintain proper trace context for distributed tracing
122188

123189
## Metrics
124190

@@ -143,6 +209,8 @@ The package uses KaibanJS-specific semantic conventions for LLM attributes that
143209
- `kaiban.llm.request.start_time` - When the thinking process started
144210
- `kaiban.llm.request.status` - Status of the request (started, interrupted, completed)
145211
- `kaiban.llm.request.input_length` - Length of the input messages
212+
- `kaiban.llm.request.has_metadata` - Whether metadata is available
213+
- `kaiban.llm.request.metadata_keys` - Available metadata keys
146214

147215
### LLM Usage Attributes (`kaiban.llm.usage.*`)
148216

@@ -161,6 +229,39 @@ The package uses KaibanJS-specific semantic conventions for LLM attributes that
161229
- `kaiban.llm.response.status` - Status of the response (completed, error, etc.)
162230
- `kaiban.llm.response.output_length` - Length of the output messages
163231

232+
### Task Attributes (`task.*`)
233+
234+
- `task.id` - Unique task identifier
235+
- `task.name` - Task title
236+
- `task.description` - Task description
237+
- `task.status` - Task status (started, completed, errored, aborted)
238+
- `task.start_time` - When task execution started
239+
- `task.end_time` - When task execution ended
240+
- `task.duration_ms` - Task execution duration in milliseconds
241+
- `task.iterations` - Number of iterations performed
242+
- `task.total_cost` - Total cost for the task
243+
- `task.total_tokens_input` - Total input tokens used
244+
- `task.total_tokens_output` - Total output tokens generated
245+
- `task.has_metadata` - Whether task has metadata
246+
- `task.metadata_keys` - Available metadata keys
247+
248+
### Agent Attributes (`agent.*`)
249+
250+
- `agent.id` - Unique agent identifier
251+
- `agent.name` - Agent name
252+
- `agent.role` - Agent role description
253+
254+
### Error Attributes (`error.*`)
255+
256+
- `error.message` - Error message
257+
- `error.type` - Error type
258+
- `error.stack` - Error stack trace
259+
260+
### Span Types
261+
262+
- `task.execute` - Task execution spans
263+
- `kaiban.agent.thinking` - Agent thinking spans (nested under task spans)
264+
164265
These conventions ensure that observability services like Langfuse, Phoenix, and others can automatically recognize and properly display LLM-related data in their dashboards.
165266

166267
## Exporters

playground/nodejs/mcp-otlp.js

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
// Assuming kaibanjs is a local module or a placeholder for demonstration purposes
2+
const { Agent, Task, Team } = require('kaibanjs');
3+
const { MultiServerMCPClient } = require('@langchain/mcp-adapters');
4+
const { enableOpenTelemetry } = require('@kaibanjs/opentelemetry');
5+
6+
require('dotenv').config({ path: './.env.local' });
7+
8+
async function main() {
9+
// ╔══════════════════════════════════════════════════════╗
10+
// ║ How to Use KaibanJS: ║
11+
// ║ 1. Define your Agents with specific roles and goals ║
12+
// ║ 2. Define the Tasks each Agent will perform ║
13+
// ║ 3. Create the Team and assign Agents and their Tasks ║
14+
// ║ 4. Start the Team to execute the defined tasks ║
15+
// ╚══════════════════════════════════════════════════════╝
16+
17+
const mcpClient = new MultiServerMCPClient({
18+
// Whether to prefix tool names with the server name (optional, default: true)
19+
prefixToolNameWithServerName: false,
20+
// Optional additional prefix for tool names (optional, default: "mcp")
21+
additionalToolNamePrefix: '',
22+
mcpServers: {
23+
tavily: {
24+
command: 'npx',
25+
args: ['-y', '[email protected]'],
26+
env: {
27+
TAVILY_API_KEY: process.env.TAVILY_API_KEY || '',
28+
PATH: process.env.PATH || '',
29+
},
30+
},
31+
},
32+
});
33+
34+
const tavilyTools = await mcpClient.getTools('tavily');
35+
const searchTool = tavilyTools.find((tool) => tool.name === 'tavily-search');
36+
37+
// ──── Agents ────────────────────────────────────────────
38+
// ─ Agents are autonomous entities designed to perform
39+
// ─ specific roles and achieve goals based on the
40+
// ─ tasks assigned to them.
41+
// ────────────────────────────────────────────────────────
42+
43+
// Define agents
44+
const searchAgent = new Agent({
45+
name: 'Scout',
46+
role: 'Information Gatherer',
47+
goal: 'Find up-to-date information about the given sports query.',
48+
background: 'Research',
49+
tools: [searchTool],
50+
});
51+
52+
const contentCreator = new Agent({
53+
name: 'Writer',
54+
role: 'Content Creator',
55+
goal: 'Generate a comprehensive articles about any sports event.',
56+
background: 'Journalism',
57+
tools: [],
58+
});
59+
60+
// Define tasks
61+
const searchTask = new Task({
62+
description: `Search for detailed information about the sports query: {sportsQuery}.`,
63+
expectedOutput:
64+
'Detailed information about the sports event. Key players, key moments, final score and other usefull information.',
65+
agent: searchAgent,
66+
});
67+
68+
const writeTask = new Task({
69+
description: `Using the gathered information, write a detailed article about the sport event.`,
70+
expectedOutput:
71+
'A well-structured and engaging sports article. With a title, introduction, body, and conclusion. Min 4 paragrahps long.',
72+
agent: contentCreator,
73+
});
74+
75+
// Team to coordinate the agents
76+
const team = new Team({
77+
name: 'Sports Content Creation Team',
78+
agents: [searchAgent, contentCreator],
79+
tasks: [searchTask, writeTask],
80+
inputs: { sportsQuery: 'Who won the Copa America in 2024?' }, // Placeholder for dynamic input
81+
env: {
82+
OPENAI_API_KEY: process.env.OPENAI_API_KEY,
83+
},
84+
// Results of the latest UEFA Champions League match.
85+
});
86+
87+
// ──── Listening to Changes────────────────────────────────────────────
88+
//
89+
// Listening to changes in the team's state is crucial for dynamic updates.
90+
// Yup...KaibanJS utilizes a store similar to Redux for state management.
91+
//
92+
// You can subscribe to specific fields or any field on the store.
93+
//──────────────────────────────────────────────────────────────────────
94+
95+
// team.subscribeToChanges(
96+
// (updatedFields) => {
97+
// console.log('Workflow Status Updated:', updatedFields);
98+
// },
99+
// ['teamWorkflowStatus']
100+
// );
101+
102+
// ──── Start Team Workflow ───────────────────────────────────────
103+
//
104+
// Begins the predefined team process, producing the final result.
105+
//─────────────────────────────────────────────────────────────────
106+
const config = {
107+
enabled: true,
108+
sampling: {
109+
rate: 1.0,
110+
strategy: 'always',
111+
},
112+
attributes: {
113+
includeSensitiveData: false,
114+
customAttributes: {
115+
'service.version': '1.0.0',
116+
'service.environment': process.env.NODE_ENV || 'development',
117+
},
118+
},
119+
exporters: {
120+
console: false, // Keep console output for debugging
121+
otlp: {
122+
endpoint: 'https://us.cloud.langfuse.com/api/public/otel/v1/traces',
123+
headers: {
124+
Authorization:
125+
'Basic ' +
126+
Buffer.from(
127+
`${process.env.LANGFUSE_PUBLIC_KEY}:${process.env.LANGFUSE_SECRET_KEY}`
128+
).toString('base64'),
129+
},
130+
serviceName: 'kaibanjs-service',
131+
timeout: 30000,
132+
compression: 'gzip',
133+
},
134+
},
135+
};
136+
enableOpenTelemetry(team, config);
137+
138+
const result = await team.start();
139+
console.log('Final Output:', result);
140+
}
141+
142+
main();

0 commit comments

Comments
 (0)