@@ -21,6 +21,13 @@ import type { ITool, ToolExecutionContext } from '../core/tools/ITool.js';
2121import { recordAgentOSTurnMetrics , withAgentOSSpan } from '../evaluation/observability/otel.js' ;
2222import type { AgentCallRecord , AgencyTraceEvent } from './types.js' ;
2323import type { IModelRouter , ModelRouteParams } from '../core/llm/routing/IModelRouter.js' ;
24+ import type {
25+ MessageContent ,
26+ MessageContentPart ,
27+ } from '../core/llm/providers/IProvider.js' ;
28+
29+ // Re-export multimodal types for downstream consumers
30+ export type { MessageContent , MessageContentPart } ;
2431
2532async function recordAgentOSUsageLazy (
2633 input : Parameters < typeof import ( './runtime/usageLedger.js' ) [ 'recordAgentOSUsage' ] > [ 0 ]
@@ -36,8 +43,21 @@ async function recordAgentOSUsageLazy(
3643export interface Message {
3744 /** Role of the message author. */
3845 role : 'system' | 'user' | 'assistant' | 'tool' ;
39- /** Plain-text or serialised-JSON content of the message. */
40- content : string ;
46+ /** Content of the message. String for text-only, array for multimodal (images + text). */
47+ content : MessageContent ;
48+ }
49+
50+ /**
51+ * Extract plain text from a MessageContent value.
52+ * For strings, returns as-is. For arrays, concatenates text parts.
53+ */
54+ export function extractTextFromContent ( content : MessageContent ) : string {
55+ if ( typeof content === 'string' ) return content ;
56+ if ( ! Array . isArray ( content ) ) return String ( content ?? '' ) ;
57+ return content
58+ . filter ( ( p ) : p is { type : 'text' ; text : string } => p . type === 'text' && typeof ( p as any ) . text === 'string' )
59+ . map ( ( p ) => p . text )
60+ . join ( '\n' ) ;
4161}
4262
4363/**
0 commit comments