fix: address second-round review findings
- Remove redundant `agent` re-declarations from trace subtypes - Change TraceEventBase.type from `string` to literal union type - Update onTrace callback type to `=> void | Promise<void>` - Add readonly to onProgress/onTrace on OrchestratorConfig - Remove Date.now() conditional guards (always capture timing) - Auto-generate runId fallback when onTrace is set without runId - Remove emitTrace from public API surface (keep generateRunId) - Add TODO comments for runParallel()/runAny() trace forwarding
This commit is contained in:
parent
8f7fc2019b
commit
e696d877e7
|
|
@ -32,7 +32,7 @@ import type {
|
|||
TokenUsage,
|
||||
ToolUseContext,
|
||||
} from '../types.js'
|
||||
import { emitTrace } from '../utils/trace.js'
|
||||
import { emitTrace, generateRunId } from '../utils/trace.js'
|
||||
import type { ToolDefinition as FrameworkToolDefinition, ToolRegistry } from '../tool/framework.js'
|
||||
import type { ToolExecutor } from '../tool/executor.js'
|
||||
import { createAdapter } from '../llm/adapter.js'
|
||||
|
|
@ -275,7 +275,7 @@ export class Agent {
|
|||
): Promise<AgentRunResult> {
|
||||
this.transitionTo('running')
|
||||
|
||||
const agentStartMs = callerOptions?.onTrace ? Date.now() : 0
|
||||
const agentStartMs = Date.now()
|
||||
|
||||
try {
|
||||
const runner = await this.getRunner()
|
||||
|
|
@ -283,9 +283,12 @@ export class Agent {
|
|||
this.state.messages.push(msg)
|
||||
callerOptions?.onMessage?.(msg)
|
||||
}
|
||||
// Auto-generate runId when onTrace is provided but runId is missing
|
||||
const needsRunId = callerOptions?.onTrace && !callerOptions.runId
|
||||
const runOptions: RunOptions = {
|
||||
...callerOptions,
|
||||
onMessage: internalOnMessage,
|
||||
...(needsRunId ? { runId: generateRunId() } : undefined),
|
||||
}
|
||||
|
||||
const result = await runner.run(messages, runOptions)
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ export class AgentPool {
|
|||
*
|
||||
* @param tasks - Array of `{ agent, prompt }` descriptors.
|
||||
*/
|
||||
// TODO(#18): accept RunOptions per task to forward trace context
|
||||
async runParallel(
|
||||
tasks: ReadonlyArray<{ readonly agent: string; readonly prompt: string }>,
|
||||
): Promise<Map<string, AgentRunResult>> {
|
||||
|
|
@ -187,6 +188,7 @@ export class AgentPool {
|
|||
*
|
||||
* @throws {Error} If the pool is empty.
|
||||
*/
|
||||
// TODO(#18): accept RunOptions to forward trace context
|
||||
async runAny(prompt: string): Promise<AgentRunResult> {
|
||||
const allAgents = this.list()
|
||||
if (allAgents.length === 0) {
|
||||
|
|
|
|||
|
|
@ -78,8 +78,8 @@ export interface RunOptions {
|
|||
readonly onToolResult?: (name: string, result: ToolResult) => void
|
||||
/** Fired after each complete {@link LLMMessage} is appended. */
|
||||
readonly onMessage?: (message: LLMMessage) => void
|
||||
/** Trace callback for observability spans. */
|
||||
readonly onTrace?: (event: TraceEvent) => void
|
||||
/** Trace callback for observability spans. Async callbacks are safe. */
|
||||
readonly onTrace?: (event: TraceEvent) => void | Promise<void>
|
||||
/** Run ID for trace correlation. */
|
||||
readonly runId?: string
|
||||
/** Task ID for trace correlation. */
|
||||
|
|
@ -264,16 +264,15 @@ export class AgentRunner {
|
|||
// ------------------------------------------------------------------
|
||||
// Step 1: Call the LLM and collect the full response for this turn.
|
||||
// ------------------------------------------------------------------
|
||||
const llmStartMs = options.onTrace ? Date.now() : 0
|
||||
const llmStartMs = Date.now()
|
||||
const response = await this.adapter.chat(conversationMessages, baseChatOptions)
|
||||
if (options.onTrace) {
|
||||
const llmEndMs = Date.now()
|
||||
const agentName = options.traceAgent ?? this.options.agentName ?? 'unknown'
|
||||
emitTrace(options.onTrace, {
|
||||
type: 'llm_call',
|
||||
runId: options.runId ?? '',
|
||||
taskId: options.taskId,
|
||||
agent: agentName,
|
||||
agent: options.traceAgent ?? this.options.agentName ?? 'unknown',
|
||||
model: this.options.model,
|
||||
turn: turns,
|
||||
tokens: response.usage,
|
||||
|
|
@ -352,12 +351,11 @@ export class AgentRunner {
|
|||
options.onToolResult?.(block.name, result)
|
||||
|
||||
if (options.onTrace) {
|
||||
const agentName = options.traceAgent ?? this.options.agentName ?? 'unknown'
|
||||
emitTrace(options.onTrace, {
|
||||
type: 'tool_call',
|
||||
runId: options.runId ?? '',
|
||||
taskId: options.taskId,
|
||||
agent: agentName,
|
||||
agent: options.traceAgent ?? this.options.agentName ?? 'unknown',
|
||||
tool: block.name,
|
||||
isError: result.isError ?? false,
|
||||
startMs: startTime,
|
||||
|
|
|
|||
|
|
@ -162,6 +162,7 @@ export type {
|
|||
OrchestratorEvent,
|
||||
|
||||
// Trace
|
||||
TraceEventType,
|
||||
TraceEventBase,
|
||||
TraceEvent,
|
||||
LLMCallTrace,
|
||||
|
|
@ -174,4 +175,4 @@ export type {
|
|||
MemoryStore,
|
||||
} from './types.js'
|
||||
|
||||
export { emitTrace, generateRunId } from './utils/trace.js'
|
||||
export { generateRunId } from './utils/trace.js'
|
||||
|
|
|
|||
13
src/types.ts
13
src/types.ts
|
|
@ -315,19 +315,22 @@ export interface OrchestratorConfig {
|
|||
readonly defaultProvider?: 'anthropic' | 'copilot' | 'openai'
|
||||
readonly defaultBaseURL?: string
|
||||
readonly defaultApiKey?: string
|
||||
onProgress?: (event: OrchestratorEvent) => void
|
||||
onTrace?: (event: TraceEvent) => void
|
||||
readonly onProgress?: (event: OrchestratorEvent) => void
|
||||
readonly onTrace?: (event: TraceEvent) => void | Promise<void>
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Trace events — lightweight observability spans
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Trace event type discriminants. */
|
||||
export type TraceEventType = 'llm_call' | 'tool_call' | 'task' | 'agent'
|
||||
|
||||
/** Shared fields present on every trace event. */
|
||||
export interface TraceEventBase {
|
||||
/** Unique identifier for the entire run (runTeam / runTasks / runAgent call). */
|
||||
readonly runId: string
|
||||
readonly type: string
|
||||
readonly type: TraceEventType
|
||||
/** Unix epoch ms when the span started. */
|
||||
readonly startMs: number
|
||||
/** Unix epoch ms when the span ended. */
|
||||
|
|
@ -343,7 +346,6 @@ export interface TraceEventBase {
|
|||
/** Emitted for each LLM API call (one per agent turn). */
|
||||
export interface LLMCallTrace extends TraceEventBase {
|
||||
readonly type: 'llm_call'
|
||||
readonly agent: string
|
||||
readonly model: string
|
||||
readonly turn: number
|
||||
readonly tokens: TokenUsage
|
||||
|
|
@ -352,7 +354,6 @@ export interface LLMCallTrace extends TraceEventBase {
|
|||
/** Emitted for each tool execution. */
|
||||
export interface ToolCallTrace extends TraceEventBase {
|
||||
readonly type: 'tool_call'
|
||||
readonly agent: string
|
||||
readonly tool: string
|
||||
readonly isError: boolean
|
||||
}
|
||||
|
|
@ -362,7 +363,6 @@ export interface TaskTrace extends TraceEventBase {
|
|||
readonly type: 'task'
|
||||
readonly taskId: string
|
||||
readonly taskTitle: string
|
||||
readonly agent: string
|
||||
readonly success: boolean
|
||||
readonly retries: number
|
||||
}
|
||||
|
|
@ -370,7 +370,6 @@ export interface TaskTrace extends TraceEventBase {
|
|||
/** Emitted when an agent run completes (wraps the full conversation loop). */
|
||||
export interface AgentTrace extends TraceEventBase {
|
||||
readonly type: 'agent'
|
||||
readonly agent: string
|
||||
readonly turns: number
|
||||
readonly tokens: TokenUsage
|
||||
readonly toolCalls: number
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import type { TraceEvent } from '../types.js'
|
|||
* subscriber never crashes agent execution.
|
||||
*/
|
||||
export function emitTrace(
|
||||
fn: ((event: TraceEvent) => void) | undefined,
|
||||
fn: ((event: TraceEvent) => void | Promise<void>) | undefined,
|
||||
event: TraceEvent,
|
||||
): void {
|
||||
if (!fn) return
|
||||
|
|
|
|||
Loading…
Reference in New Issue