@nebulaos/core 0.2.3 → 0.2.5

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.
@@ -1,4 +1,4 @@
1
- import { IModel, Message, ToolCall, StreamChunk, ProviderResponse, ContentPart } from "./provider/index.js";
1
+ import { IModel, Message, ToolCall, TokenUsage, StreamChunk, ProviderResponse, ContentPart } from "./provider/index.js";
2
2
  import { IMemory, MemoryExecutionContext } from "./memory/index.js";
3
3
  import { Tool, ToolExecution } from "./tools/index.js";
4
4
  import { ISkill } from "./skills/index.js";
@@ -51,6 +51,7 @@ export type AgentResult = {
51
51
  llmCalls: number;
52
52
  totalDurationMs: number;
53
53
  truncated: boolean;
54
+ usage?: TokenUsage;
54
55
  };
55
56
  export type AgentStreamChunk = StreamChunk | {
56
57
  type: "tool_result";
@@ -8,6 +8,7 @@ const agent_logger_js_1 = require("../logger/agent-logger.js");
8
8
  const index_js_3 = require("../tracing/index.js");
9
9
  const BaseAgent_js_1 = require("./BaseAgent.js");
10
10
  const index_js_4 = require("../execution-context/index.js");
11
+ const types_1 = require("@nebulaos/types");
11
12
  function generateCorrelationId() {
12
13
  return `exec_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
13
14
  }
@@ -155,262 +156,272 @@ class Agent extends BaseAgent_js_1.BaseAgent {
155
156
  let llmCalls = 0;
156
157
  let truncated = false;
157
158
  let totalUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
158
- const runWithExecutionContext = async () => index_js_3.Tracing.withSpan({
159
- kind: "agent",
160
- name: `agent:${this.name}`,
161
- correlationId,
162
- executionId: options.executionId,
163
- data: { agentName: this.name, input },
164
- }, async (agentSpan) => {
165
- this.emit("agent:execution:start", {
159
+ const runWithExecutionContext = async () => {
160
+ const agentStart = {
161
+ agentName: this.name,
162
+ input,
163
+ };
164
+ return index_js_3.Tracing.withSpan({
165
+ kind: types_1.SpanType.agent,
166
+ name: `agent:${this.name}`,
166
167
  correlationId,
167
168
  executionId: options.executionId,
168
- data: {
169
- agentId: this.id,
170
- agentName: this.name,
171
- input,
172
- },
173
- });
174
- try {
175
- // Initialize skills if not already initialized
176
- await this.initializeSkills();
177
- if (input) {
178
- await this.addMessage({ role: "user", content: input }, memoryCtx);
179
- }
180
- let step = 0;
181
- while (step < maxSteps) {
182
- step++;
169
+ data: agentStart,
170
+ }, async (agentSpan) => {
171
+ this.emit("agent:execution:start", {
172
+ correlationId,
173
+ executionId: options.executionId,
174
+ data: {
175
+ agentId: this.id,
176
+ agentName: this.name,
177
+ input,
178
+ },
179
+ });
180
+ try {
181
+ // Initialize skills if not already initialized
182
+ await this.initializeSkills();
183
+ if (input) {
184
+ await this.addMessage({ role: "user", content: input }, memoryCtx);
185
+ }
186
+ let step = 0;
187
+ while (step < maxSteps) {
188
+ step++;
189
+ llmCalls++;
190
+ let messages = await this.getMessagesWithContext(memoryCtx);
191
+ let tools = !options.disableTools && this.config.tools ? [...this.config.tools] : [];
192
+ // Apply Request Interceptors
193
+ let context = { messages, tools };
194
+ for (const interceptor of this.requestInterceptors) {
195
+ context = await interceptor(context);
196
+ }
197
+ messages = context.messages;
198
+ tools = context.tools;
199
+ this.validateMessagesForModel(messages, {
200
+ maxFileBytes: MAX_MESSAGE_FILE_BYTES_DEFAULT,
201
+ providerName: this.config.model.providerName,
202
+ modelName: this.config.model.modelName,
203
+ capabilities: this.config.model.capabilities,
204
+ });
205
+ const llmTools = tools.length > 0
206
+ ? tools.map(t => t.toLLMDefinition())
207
+ : undefined;
208
+ this.emit("agent:llm:call", {
209
+ correlationId,
210
+ executionId: options.executionId,
211
+ data: {
212
+ agentId: this.id,
213
+ agentName: this.name,
214
+ step,
215
+ messages,
216
+ tools: llmTools,
217
+ responseFormat: options.responseFormat,
218
+ model: {
219
+ provider: this.config.model.providerName,
220
+ model: this.config.model.modelName,
221
+ },
222
+ },
223
+ });
224
+ // No SDK-side LLM span: the LLM Gateway creates its own span
225
+ // with richer data. We just call generate under the agent span so
226
+ // the provider can read the current trace context (traceparent).
227
+ const rawResponse = await this.config.model.generate(messages, llmTools, {
228
+ responseFormat: options.responseFormat,
229
+ });
230
+ let response = rawResponse;
231
+ this.emit("agent:llm:response", {
232
+ correlationId,
233
+ executionId: options.executionId,
234
+ data: {
235
+ agentId: this.id,
236
+ agentName: this.name,
237
+ step,
238
+ content: response.content,
239
+ toolCalls: response.toolCalls,
240
+ usage: response.usage,
241
+ model: {
242
+ provider: this.config.model.providerName,
243
+ model: this.config.model.modelName,
244
+ },
245
+ },
246
+ });
247
+ // Accumulate token usage
248
+ if (response.usage) {
249
+ totalUsage.promptTokens += response.usage.promptTokens;
250
+ totalUsage.completionTokens += response.usage.completionTokens;
251
+ totalUsage.totalTokens += response.usage.totalTokens;
252
+ if (response.usage.reasoningTokens) {
253
+ totalUsage.reasoningTokens = (totalUsage.reasoningTokens || 0) + response.usage.reasoningTokens;
254
+ }
255
+ }
256
+ if (!response.toolCalls || response.toolCalls.length === 0 || options.disableTools) {
257
+ // Apply Response Interceptors (Final Answer)
258
+ for (const interceptor of this.responseInterceptors) {
259
+ response = await interceptor(response);
260
+ }
261
+ await this.addMessage({ role: "assistant", content: response.content }, memoryCtx);
262
+ const agentEnd = {
263
+ output: options.responseFormat?.type === "json"
264
+ ? this.safeParseJson(response.content)
265
+ : response.content,
266
+ usage: totalUsage,
267
+ };
268
+ await agentSpan.end({
269
+ status: "success",
270
+ data: agentEnd,
271
+ });
272
+ return this.finishResult({
273
+ correlationId,
274
+ executionId: options.executionId,
275
+ content: options.responseFormat?.type === "json"
276
+ ? this.safeParseJson(response.content)
277
+ : response.content,
278
+ toolExecutions,
279
+ toolCalls: options.disableTools ? response.toolCalls : undefined,
280
+ llmCalls,
281
+ totalDurationMs: Date.now() - startTime,
282
+ truncated: false,
283
+ totalUsage,
284
+ });
285
+ }
286
+ // Add assistant message with tool calls before executing tools
287
+ await this.addMessage({
288
+ role: "assistant",
289
+ content: response.content,
290
+ tool_calls: response.toolCalls
291
+ }, memoryCtx);
292
+ for (const toolCall of response.toolCalls) {
293
+ const parentExec = index_js_4.ExecutionContext.getOrUndefined();
294
+ const toolExecutionId = parentExec?.executionId || options.executionId ? (0, node_crypto_1.randomUUID)() : undefined;
295
+ const toolStart = {
296
+ toolName: toolCall.function.name,
297
+ toolCallId: toolCall.id,
298
+ args: toolCall.function.arguments,
299
+ };
300
+ await index_js_3.Tracing.withSpan({
301
+ kind: types_1.SpanType.tool,
302
+ name: `tool:${toolCall.function.name}`,
303
+ correlationId,
304
+ executionId: toolExecutionId ?? options.executionId,
305
+ data: toolStart,
306
+ }, async (toolSpan) => {
307
+ this.emit("agent:tool:call", {
308
+ correlationId,
309
+ executionId: options.executionId,
310
+ data: {
311
+ agentId: this.id,
312
+ agentName: this.name,
313
+ toolName: toolCall.function.name,
314
+ toolCallId: toolCall.id,
315
+ args: toolCall.function.arguments,
316
+ },
317
+ });
318
+ const execution = await this.executeToolCall(toolCall, toolExecutionId);
319
+ toolExecutions.push(execution);
320
+ collectedToolCalls.push(toolCall);
321
+ this.emit("agent:tool:result", {
322
+ correlationId,
323
+ executionId: options.executionId,
324
+ data: {
325
+ agentId: this.id,
326
+ agentName: this.name,
327
+ toolName: toolCall.function.name,
328
+ toolCallId: toolCall.id,
329
+ output: execution.output,
330
+ error: execution.error,
331
+ durationMs: execution.durationMs,
332
+ },
333
+ });
334
+ const toolEnd = execution.error
335
+ ? { error: execution.error }
336
+ : { output: execution.output };
337
+ await toolSpan.end({
338
+ status: execution.error ? "error" : "success",
339
+ data: toolEnd,
340
+ });
341
+ await this.addMessage({
342
+ role: "tool",
343
+ tool_call_id: toolCall.id,
344
+ content: execution.error ? `Error: ${execution.error}` : JSON.stringify(execution.output),
345
+ }, memoryCtx);
346
+ });
347
+ }
348
+ }
349
+ truncated = true;
183
350
  llmCalls++;
184
- let messages = await this.getMessagesWithContext(memoryCtx);
185
- let tools = !options.disableTools && this.config.tools ? [...this.config.tools] : [];
186
- // Apply Request Interceptors
187
- let context = { messages, tools };
351
+ // Final run after max steps (force answer)
352
+ let finalMessages = await this.getMessagesWithContext(memoryCtx);
353
+ let finalTools = !options.disableTools && this.config.tools ? [...this.config.tools] : [];
354
+ // Interceptors for final run
355
+ let context = { messages: finalMessages, tools: finalTools };
188
356
  for (const interceptor of this.requestInterceptors) {
189
357
  context = await interceptor(context);
190
358
  }
191
- messages = context.messages;
192
- tools = context.tools;
193
- this.validateMessagesForModel(messages, {
359
+ finalMessages = context.messages;
360
+ // We ignore tools for final run usually, but keep consistency
361
+ this.validateMessagesForModel(finalMessages, {
194
362
  maxFileBytes: MAX_MESSAGE_FILE_BYTES_DEFAULT,
195
363
  providerName: this.config.model.providerName,
196
364
  modelName: this.config.model.modelName,
197
365
  capabilities: this.config.model.capabilities,
198
366
  });
199
- const llmTools = tools.length > 0
200
- ? tools.map(t => t.toLLMDefinition())
201
- : undefined;
202
- this.emit("agent:llm:call", {
367
+ let finalResponse = await this.config.model.generate(finalMessages);
368
+ // Response interceptors for final run
369
+ for (const interceptor of this.responseInterceptors) {
370
+ finalResponse = await interceptor(finalResponse);
371
+ }
372
+ await this.addMessage({ role: "assistant", content: finalResponse.content }, memoryCtx);
373
+ const agentEndTruncated = {
374
+ output: finalResponse.content,
375
+ usage: totalUsage,
376
+ };
377
+ await agentSpan.end({
378
+ status: truncated ? "cancelled" : "success",
379
+ data: agentEndTruncated,
380
+ });
381
+ return this.finishResult({
203
382
  correlationId,
204
383
  executionId: options.executionId,
205
- data: {
206
- agentId: this.id,
207
- agentName: this.name,
208
- step,
209
- messages,
210
- tools: llmTools,
211
- responseFormat: options.responseFormat,
212
- model: {
213
- provider: this.config.model.providerName,
214
- model: this.config.model.modelName,
215
- },
216
- },
217
- });
218
- // No SDK-side LLM span: the LLM Gateway creates its own span
219
- // with richer data. We just call generate under the agent span so
220
- // the provider can read the current trace context (traceparent).
221
- const rawResponse = await this.config.model.generate(messages, llmTools, {
222
- responseFormat: options.responseFormat,
384
+ content: finalResponse.content,
385
+ toolExecutions,
386
+ toolCalls: collectedToolCalls,
387
+ llmCalls,
388
+ totalDurationMs: Date.now() - startTime,
389
+ truncated,
390
+ totalUsage,
223
391
  });
224
- let response = rawResponse;
225
- this.emit("agent:llm:response", {
392
+ }
393
+ catch (err) {
394
+ const error = err instanceof Error ? err : new Error(String(err));
395
+ this.emit("agent:execution:error", {
226
396
  correlationId,
227
397
  executionId: options.executionId,
228
398
  data: {
229
399
  agentId: this.id,
230
400
  agentName: this.name,
231
- step,
232
- content: response.content,
233
- toolCalls: response.toolCalls,
234
- usage: response.usage,
235
- model: {
236
- provider: this.config.model.providerName,
237
- model: this.config.model.modelName,
401
+ error: {
402
+ message: error.message,
403
+ stack: error.stack,
404
+ name: error.name,
238
405
  },
406
+ durationMs: Date.now() - startTime,
239
407
  },
240
408
  });
241
- // Accumulate token usage
242
- if (response.usage) {
243
- totalUsage.promptTokens += response.usage.promptTokens;
244
- totalUsage.completionTokens += response.usage.completionTokens;
245
- totalUsage.totalTokens += response.usage.totalTokens;
246
- if (response.usage.reasoningTokens) {
247
- totalUsage.reasoningTokens = (totalUsage.reasoningTokens || 0) + response.usage.reasoningTokens;
248
- }
249
- }
250
- if (!response.toolCalls || response.toolCalls.length === 0 || options.disableTools) {
251
- // Apply Response Interceptors (Final Answer)
252
- for (const interceptor of this.responseInterceptors) {
253
- response = await interceptor(response);
254
- }
255
- await this.addMessage({ role: "assistant", content: response.content }, memoryCtx);
256
- await agentSpan.end({
257
- status: "success",
258
- data: {
259
- output: options.responseFormat?.type === "json"
260
- ? this.safeParseJson(response.content)
261
- : response.content,
262
- usage: totalUsage,
263
- },
264
- });
265
- return this.finishResult({
266
- correlationId,
267
- executionId: options.executionId,
268
- content: options.responseFormat?.type === "json"
269
- ? this.safeParseJson(response.content)
270
- : response.content,
271
- toolExecutions,
272
- toolCalls: options.disableTools ? response.toolCalls : undefined,
273
- llmCalls,
274
- totalDurationMs: Date.now() - startTime,
275
- truncated: false,
276
- totalUsage,
277
- });
278
- }
279
- // Add assistant message with tool calls before executing tools
280
- await this.addMessage({
281
- role: "assistant",
282
- content: response.content,
283
- tool_calls: response.toolCalls
284
- }, memoryCtx);
285
- for (const toolCall of response.toolCalls) {
286
- const parentExec = index_js_4.ExecutionContext.getOrUndefined();
287
- const toolExecutionId = parentExec?.executionId || options.executionId ? (0, node_crypto_1.randomUUID)() : undefined;
288
- await index_js_3.Tracing.withSpan({
289
- kind: "tool",
290
- name: `tool:${toolCall.function.name}`,
291
- correlationId,
292
- executionId: toolExecutionId ?? options.executionId,
293
- data: {
294
- toolName: toolCall.function.name,
295
- toolCallId: toolCall.id,
296
- args: toolCall.function.arguments,
297
- },
298
- }, async (toolSpan) => {
299
- this.emit("agent:tool:call", {
300
- correlationId,
301
- executionId: options.executionId,
302
- data: {
303
- agentId: this.id,
304
- agentName: this.name,
305
- toolName: toolCall.function.name,
306
- toolCallId: toolCall.id,
307
- args: toolCall.function.arguments,
308
- },
309
- });
310
- const execution = await this.executeToolCall(toolCall, toolExecutionId);
311
- toolExecutions.push(execution);
312
- collectedToolCalls.push(toolCall);
313
- this.emit("agent:tool:result", {
314
- correlationId,
315
- executionId: options.executionId,
316
- data: {
317
- agentId: this.id,
318
- agentName: this.name,
319
- toolName: toolCall.function.name,
320
- toolCallId: toolCall.id,
321
- output: execution.output,
322
- error: execution.error,
323
- durationMs: execution.durationMs,
324
- },
325
- });
326
- await toolSpan.end({
327
- status: execution.error ? "error" : "success",
328
- data: {
329
- output: execution.output,
330
- error: execution.error,
331
- },
332
- });
333
- await this.addMessage({
334
- role: "tool",
335
- tool_call_id: toolCall.id,
336
- content: execution.error ? `Error: ${execution.error}` : JSON.stringify(execution.output),
337
- }, memoryCtx);
338
- });
339
- }
340
- }
341
- truncated = true;
342
- llmCalls++;
343
- // Final run after max steps (force answer)
344
- let finalMessages = await this.getMessagesWithContext(memoryCtx);
345
- let finalTools = !options.disableTools && this.config.tools ? [...this.config.tools] : [];
346
- // Interceptors for final run
347
- let context = { messages: finalMessages, tools: finalTools };
348
- for (const interceptor of this.requestInterceptors) {
349
- context = await interceptor(context);
350
- }
351
- finalMessages = context.messages;
352
- // We ignore tools for final run usually, but keep consistency
353
- this.validateMessagesForModel(finalMessages, {
354
- maxFileBytes: MAX_MESSAGE_FILE_BYTES_DEFAULT,
355
- providerName: this.config.model.providerName,
356
- modelName: this.config.model.modelName,
357
- capabilities: this.config.model.capabilities,
358
- });
359
- let finalResponse = await this.config.model.generate(finalMessages);
360
- // Response interceptors for final run
361
- for (const interceptor of this.responseInterceptors) {
362
- finalResponse = await interceptor(finalResponse);
363
- }
364
- await this.addMessage({ role: "assistant", content: finalResponse.content }, memoryCtx);
365
- await agentSpan.end({
366
- status: truncated ? "cancelled" : "success",
367
- data: {
368
- output: finalResponse.content,
369
- usage: totalUsage,
370
- },
371
- });
372
- return this.finishResult({
373
- correlationId,
374
- executionId: options.executionId,
375
- content: finalResponse.content,
376
- toolExecutions,
377
- toolCalls: collectedToolCalls,
378
- llmCalls,
379
- totalDurationMs: Date.now() - startTime,
380
- truncated,
381
- totalUsage,
382
- });
383
- }
384
- catch (err) {
385
- const error = err instanceof Error ? err : new Error(String(err));
386
- this.emit("agent:execution:error", {
387
- correlationId,
388
- executionId: options.executionId,
389
- data: {
390
- agentId: this.id,
391
- agentName: this.name,
392
- error: {
393
- message: error.message,
394
- stack: error.stack,
395
- name: error.name,
396
- },
397
- durationMs: Date.now() - startTime,
398
- },
399
- });
400
- await agentSpan.end({
401
- status: "error",
402
- data: {
409
+ const agentEndError = {
403
410
  error: {
404
411
  message: error.message,
405
412
  name: error.name,
406
413
  code: error.code,
407
414
  status: error.status,
408
415
  },
409
- },
410
- });
411
- throw err;
412
- }
413
- });
416
+ };
417
+ await agentSpan.end({
418
+ status: "error",
419
+ data: agentEndError,
420
+ });
421
+ throw err;
422
+ }
423
+ });
424
+ };
414
425
  // Ensure execution hierarchy is available for tool sub-executions.
415
426
  // IMPORTANT: Do NOT override an existing ExecutionContext (e.g. when this agent is a sub-execution inside a workflow).
416
427
  const existingExecContext = index_js_4.ExecutionContext.getOrUndefined();
@@ -560,16 +571,17 @@ class Agent extends BaseAgent_js_1.BaseAgent {
560
571
  }
561
572
  await this.addMessage({ role: "assistant", content: fullContent || null, tool_calls: toolCalls }, memoryCtx);
562
573
  for (const toolCall of toolCalls) {
574
+ const toolStartStream = {
575
+ toolName: toolCall.function.name,
576
+ toolCallId: toolCall.id,
577
+ args: toolCall.function.arguments,
578
+ };
563
579
  const execution = await index_js_3.Tracing.withSpan({
564
- kind: "tool",
580
+ kind: types_1.SpanType.tool,
565
581
  name: `tool:${toolCall.function.name}`,
566
582
  correlationId,
567
583
  executionId: options.executionId,
568
- data: {
569
- toolName: toolCall.function.name,
570
- toolCallId: toolCall.id,
571
- args: toolCall.function.arguments,
572
- },
584
+ data: toolStartStream,
573
585
  }, async (toolSpan) => {
574
586
  this.emit("agent:tool:call", {
575
587
  correlationId,
@@ -598,9 +610,12 @@ class Agent extends BaseAgent_js_1.BaseAgent {
598
610
  durationMs: exec.durationMs,
599
611
  },
600
612
  });
613
+ const toolEndStream = exec.error
614
+ ? { error: exec.error }
615
+ : { output: exec.output };
601
616
  await toolSpan.end({
602
617
  status: exec.error ? "error" : "success",
603
- data: { output: exec.output, error: exec.error },
618
+ data: toolEndStream,
604
619
  });
605
620
  return exec;
606
621
  });
@@ -870,6 +885,7 @@ class Agent extends BaseAgent_js_1.BaseAgent {
870
885
  llmCalls: params.llmCalls,
871
886
  totalDurationMs: params.totalDurationMs,
872
887
  truncated: params.truncated,
888
+ usage: params.totalUsage,
873
889
  };
874
890
  this.emit("agent:execution:end", {
875
891
  correlationId: params.correlationId,
@@ -21,12 +21,16 @@ class CommitteeTeam extends BaseAgent_js_1.BaseAgent {
21
21
  async execute(input, options) {
22
22
  const correlationId = `committee_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
23
23
  const startTime = Date.now();
24
+ const startData = {
25
+ agentName: this.name,
26
+ input,
27
+ };
24
28
  return index_js_1.Tracing.withSpan({
25
29
  kind: "agent",
26
30
  name: `team:committee:${this.name}`,
27
31
  correlationId,
28
32
  executionId: options?.executionId,
29
- data: { agentName: this.name, input },
33
+ data: startData,
30
34
  }, async (teamSpan) => {
31
35
  this.emit("agent:execution:start", {
32
36
  correlationId,
@@ -73,9 +77,10 @@ class CommitteeTeam extends BaseAgent_js_1.BaseAgent {
73
77
  durationMs: Date.now() - startTime,
74
78
  },
75
79
  });
80
+ const endData = { output: result.content };
76
81
  await teamSpan.end({
77
82
  status: result.truncated ? "cancelled" : "success",
78
- data: { output: result.content },
83
+ data: endData,
79
84
  });
80
85
  return result;
81
86
  }
@@ -95,7 +100,8 @@ class CommitteeTeam extends BaseAgent_js_1.BaseAgent {
95
100
  durationMs: Date.now() - startTime,
96
101
  },
97
102
  });
98
- await teamSpan.end({ status: "error" });
103
+ const errorData = { error: { message: err.message, name: err.name } };
104
+ await teamSpan.end({ status: "error", data: errorData });
99
105
  throw error;
100
106
  }
101
107
  });
@@ -23,12 +23,16 @@ class HandoffTeam extends BaseAgent_js_1.BaseAgent {
23
23
  async execute(input, options) {
24
24
  const correlationId = `handoff_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
25
25
  const startTime = Date.now();
26
+ const startData = {
27
+ agentName: this.name,
28
+ input,
29
+ };
26
30
  return index_js_2.Tracing.withSpan({
27
31
  kind: "agent",
28
32
  name: `team:handoff:${this.name}`,
29
33
  correlationId,
30
34
  executionId: options?.executionId,
31
- data: { agentName: this.name, input },
35
+ data: startData,
32
36
  }, async (teamSpan) => {
33
37
  this.emit("agent:execution:start", {
34
38
  correlationId,
@@ -84,9 +88,10 @@ class HandoffTeam extends BaseAgent_js_1.BaseAgent {
84
88
  durationMs: Date.now() - startTime,
85
89
  },
86
90
  });
91
+ const endData = { output: result.content };
87
92
  await teamSpan.end({
88
93
  status: result.truncated ? "cancelled" : "success",
89
- data: { output: result.content },
94
+ data: endData,
90
95
  });
91
96
  return result;
92
97
  }
@@ -132,7 +137,8 @@ class HandoffTeam extends BaseAgent_js_1.BaseAgent {
132
137
  durationMs: Date.now() - startTime,
133
138
  },
134
139
  });
135
- await teamSpan.end({ status: "error" });
140
+ const errorData = { error: { message: err.message, name: err.name } };
141
+ await teamSpan.end({ status: "error", data: errorData });
136
142
  throw error;
137
143
  }
138
144
  });
@@ -26,12 +26,16 @@ class HierarchicalTeam extends BaseAgent_js_1.BaseAgent {
26
26
  async execute(input, options) {
27
27
  const correlationId = `hierarchical_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
28
28
  const startTime = Date.now();
29
+ const startData = {
30
+ agentName: this.name,
31
+ input,
32
+ };
29
33
  return index_js_1.Tracing.withSpan({
30
34
  kind: "agent",
31
35
  name: `team:hierarchical:${this.name}`,
32
36
  correlationId,
33
37
  executionId: options?.executionId,
34
- data: { agentName: this.name, input },
38
+ data: startData,
35
39
  }, async (teamSpan) => {
36
40
  this.emit("agent:execution:start", {
37
41
  correlationId,
@@ -57,9 +61,10 @@ class HierarchicalTeam extends BaseAgent_js_1.BaseAgent {
57
61
  durationMs: Date.now() - startTime,
58
62
  },
59
63
  });
64
+ const endData = { output: result.content };
60
65
  await teamSpan.end({
61
66
  status: result.truncated ? "cancelled" : "success",
62
- data: { output: result.content },
67
+ data: endData,
63
68
  });
64
69
  return result;
65
70
  }
@@ -79,7 +84,8 @@ class HierarchicalTeam extends BaseAgent_js_1.BaseAgent {
79
84
  durationMs: Date.now() - startTime,
80
85
  },
81
86
  });
82
- await teamSpan.end({ status: "error" });
87
+ const errorData = { error: { message: err.message, name: err.name } };
88
+ await teamSpan.end({ status: "error", data: errorData });
83
89
  throw error;
84
90
  }
85
91
  });
@@ -18,12 +18,16 @@ class PipelineTeam extends BaseAgent_js_1.BaseAgent {
18
18
  async execute(input, options) {
19
19
  const correlationId = `pipeline_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
20
20
  const startTime = Date.now();
21
+ const startData = {
22
+ agentName: this.name,
23
+ input,
24
+ };
21
25
  return index_js_1.Tracing.withSpan({
22
26
  kind: "agent",
23
27
  name: `team:pipeline:${this.name}`,
24
28
  correlationId,
25
29
  executionId: options?.executionId,
26
- data: { agentName: this.name, input },
30
+ data: startData,
27
31
  }, async (teamSpan) => {
28
32
  this.emit("agent:execution:start", {
29
33
  correlationId,
@@ -61,9 +65,10 @@ class PipelineTeam extends BaseAgent_js_1.BaseAgent {
61
65
  durationMs: Date.now() - startTime,
62
66
  },
63
67
  });
68
+ const endData = { output: result.content };
64
69
  await teamSpan.end({
65
70
  status: result.truncated ? "cancelled" : "success",
66
- data: { output: result.content },
71
+ data: endData,
67
72
  });
68
73
  return result;
69
74
  }
@@ -83,7 +88,8 @@ class PipelineTeam extends BaseAgent_js_1.BaseAgent {
83
88
  durationMs: Date.now() - startTime,
84
89
  },
85
90
  });
86
- await teamSpan.end({ status: "error" });
91
+ const errorData = { error: { message: err.message, name: err.name } };
92
+ await teamSpan.end({ status: "error", data: errorData });
87
93
  throw error;
88
94
  }
89
95
  });
@@ -19,12 +19,16 @@ class RouterTeam extends BaseAgent_js_1.BaseAgent {
19
19
  async execute(input, options) {
20
20
  const correlationId = `router_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`;
21
21
  const startTime = Date.now();
22
+ const startData = {
23
+ agentName: this.name,
24
+ input,
25
+ };
22
26
  return index_js_1.Tracing.withSpan({
23
27
  kind: "agent",
24
28
  name: `team:router:${this.name}`,
25
29
  correlationId,
26
30
  executionId: options?.executionId,
27
- data: { agentName: this.name, input },
31
+ data: startData,
28
32
  }, async (teamSpan) => {
29
33
  this.emit("agent:execution:start", {
30
34
  correlationId,
@@ -59,9 +63,10 @@ class RouterTeam extends BaseAgent_js_1.BaseAgent {
59
63
  // Usage? Ideally aggregated, but for now passing result content is key
60
64
  },
61
65
  });
66
+ const endData = { output: result.content, usage: result.usage };
62
67
  await teamSpan.end({
63
68
  status: result.truncated ? "cancelled" : "success",
64
- data: { output: result.content },
69
+ data: endData
65
70
  });
66
71
  return result;
67
72
  }
@@ -81,7 +86,13 @@ class RouterTeam extends BaseAgent_js_1.BaseAgent {
81
86
  durationMs: Date.now() - startTime,
82
87
  },
83
88
  });
84
- await teamSpan.end({ status: "error" });
89
+ const errorData = {
90
+ error: { message: err.message, name: err.name, code: err.code, status: err.status }
91
+ };
92
+ await teamSpan.end({
93
+ status: "error",
94
+ data: errorData
95
+ });
85
96
  throw error;
86
97
  }
87
98
  });
@@ -45,8 +45,6 @@ class ActiveSpan {
45
45
  span: {
46
46
  kind: this.kind,
47
47
  name: this.name,
48
- // The contract expects a kind-specific shape, but we keep this generic here.
49
- // The callers are responsible for providing kind-specific keys.
50
48
  data: input.data,
51
49
  },
52
50
  };
@@ -11,8 +11,12 @@ class WorkflowTelemetry {
11
11
  data: { workflowId: input.workflowId, input: input.workflowInput },
12
12
  }, async (span) => {
13
13
  const result = await fn();
14
+ const endData = { output: result };
14
15
  if (!span.isEnded)
15
- await span.end({ status: "success" });
16
+ await span.end({
17
+ status: "success",
18
+ data: endData
19
+ });
16
20
  return result;
17
21
  });
18
22
  }
@@ -30,11 +34,17 @@ class WorkflowTelemetry {
30
34
  }, async (span) => {
31
35
  try {
32
36
  const result = await fn();
33
- await span.end({ status: "success", data: { output: result } });
37
+ const successData = { output: result };
38
+ await span.end({ status: "success", data: successData });
34
39
  return result;
35
40
  }
36
41
  catch (e) {
37
- await span.end({ status: "error" });
42
+ const err = e instanceof Error ? e : new Error(String(e));
43
+ const errorData = { error: { message: err.message, name: err.name } };
44
+ await span.end({
45
+ status: "error",
46
+ data: errorData
47
+ });
38
48
  throw e;
39
49
  }
40
50
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nebulaos/core",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Core primitives for NebulaOS (Agent, Workflow, Providers)",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  "uuid": "^9.0.1",
34
34
  "zod": "^3.0.0",
35
35
  "zod-to-json-schema": "^3.0.0",
36
- "@nebulaos/types": "0.1.2"
36
+ "@nebulaos/types": "^0.1.4"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/jest": "^30.0.0",
@@ -43,9 +43,9 @@
43
43
  "jest": "^30.2.0",
44
44
  "ts-jest": "^29.4.6",
45
45
  "typescript": "^5.0.0",
46
- "@nebulaos/google-gemini": "0.0.1",
47
46
  "@nebulaos/oci": "0.0.1",
48
- "@nebulaos/openai": "0.1.0"
47
+ "@nebulaos/openai": "0.1.0",
48
+ "@nebulaos/google-gemini": "0.0.1"
49
49
  },
50
50
  "scripts": {
51
51
  "build": "tsc",