@company-semantics/contracts 0.24.0 → 0.25.1
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/package.json +4 -1
- package/src/guards/config.ts +2 -0
- package/src/index.ts +30 -0
- package/src/mcp/index.ts +18 -0
- package/src/message-parts/builder.ts +186 -0
- package/src/message-parts/index.ts +37 -0
- package/src/message-parts/types.ts +156 -0
- package/src/message-parts/wire.ts +40 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@company-semantics/contracts",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -59,6 +59,9 @@
|
|
|
59
59
|
"test": "vitest run scripts/ci/__tests__"
|
|
60
60
|
},
|
|
61
61
|
"packageManager": "pnpm@10.25.0",
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": "22.x"
|
|
64
|
+
},
|
|
62
65
|
"devDependencies": {
|
|
63
66
|
"@types/node": "^25.0.3",
|
|
64
67
|
"husky": "^9.1.7",
|
package/src/guards/config.ts
CHANGED
|
@@ -392,6 +392,8 @@ export interface GuardCheckRegistry {
|
|
|
392
392
|
structural?: BoundGuardCheck[];
|
|
393
393
|
behavioral?: BoundGuardCheck[];
|
|
394
394
|
invariants?: BoundGuardCheck[];
|
|
395
|
+
/** Evolution guards: drift detection (advisory only) */
|
|
396
|
+
evolution?: BoundGuardCheck[];
|
|
395
397
|
/** Meta-guards: protect the guard system itself (coverage correctness) */
|
|
396
398
|
meta?: BoundGuardCheck[];
|
|
397
399
|
};
|
package/src/index.ts
CHANGED
|
@@ -99,4 +99,34 @@ export type {
|
|
|
99
99
|
MCPToolDescriptor,
|
|
100
100
|
ToolDiscoveryResponse,
|
|
101
101
|
ToolListMessagePart,
|
|
102
|
+
ToolListDataPart,
|
|
102
103
|
} from './mcp/index.js'
|
|
104
|
+
|
|
105
|
+
// Message part types and builder functions
|
|
106
|
+
// @see ADR-2026-01-022 for design rationale
|
|
107
|
+
export type {
|
|
108
|
+
TextPart,
|
|
109
|
+
ToolListPart,
|
|
110
|
+
StatusPanelPart,
|
|
111
|
+
StatusPanelEntry,
|
|
112
|
+
ChartPart,
|
|
113
|
+
ChartDataPoint,
|
|
114
|
+
TablePart,
|
|
115
|
+
ConfirmationPart,
|
|
116
|
+
SurfacePart,
|
|
117
|
+
AssistantMessagePart,
|
|
118
|
+
PartBuilderState,
|
|
119
|
+
AddPartResult,
|
|
120
|
+
} from './message-parts/index.js'
|
|
121
|
+
|
|
122
|
+
export {
|
|
123
|
+
isTextPart,
|
|
124
|
+
isSurfacePart,
|
|
125
|
+
createPartBuilder,
|
|
126
|
+
addText,
|
|
127
|
+
addSurface,
|
|
128
|
+
addPart,
|
|
129
|
+
buildParts,
|
|
130
|
+
getDroppedCount,
|
|
131
|
+
WireSurfaceBuilder,
|
|
132
|
+
} from './message-parts/index.js'
|
package/src/mcp/index.ts
CHANGED
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* Types for tool discovery flow (read-only, UI-first).
|
|
5
5
|
* Same descriptor used for discovery and invocation, different fields matter.
|
|
6
6
|
*
|
|
7
|
+
* TWO SHAPES (same conceptual data, different layers):
|
|
8
|
+
* - ToolDiscoveryResponse: HTTP transport (GET /api/capabilities/tools response)
|
|
9
|
+
* - ToolListMessagePart: Chat protocol (atomic message part in conversation)
|
|
10
|
+
*
|
|
7
11
|
* INVARIANTS:
|
|
8
12
|
* - Discovery is descriptive (never executes)
|
|
9
13
|
* - Invocation is authoritative (runtime is executor)
|
|
@@ -83,3 +87,17 @@ export interface ToolListMessagePart {
|
|
|
83
87
|
type: 'tool-list'
|
|
84
88
|
tools: MCPToolDescriptor[]
|
|
85
89
|
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Wire protocol type for tool list data part.
|
|
93
|
+
*
|
|
94
|
+
* Transport-level type (SSE stream part).
|
|
95
|
+
* Uses AI SDK's `data-{name}` convention for custom data parts.
|
|
96
|
+
*
|
|
97
|
+
* The `data-` prefix signals to the AI SDK that this is a custom data part.
|
|
98
|
+
* Frontend normalizes this to `tool-list` for semantic handling.
|
|
99
|
+
*/
|
|
100
|
+
export interface ToolListDataPart {
|
|
101
|
+
type: 'data-tool-list'
|
|
102
|
+
data: { tools: MCPToolDescriptor[] }
|
|
103
|
+
}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Part Builder Functions
|
|
3
|
+
*
|
|
4
|
+
* Functional builder for constructing well-ordered message parts.
|
|
5
|
+
* Enforces invariant: narrative (text) parts before surface parts.
|
|
6
|
+
*
|
|
7
|
+
* STATE MACHINE MODEL:
|
|
8
|
+
* PartBuilder implements a two-state machine:
|
|
9
|
+
*
|
|
10
|
+
* NarrativeState → accepts text or surface
|
|
11
|
+
* SurfaceState → accepts surface only (text rejected)
|
|
12
|
+
*
|
|
13
|
+
* Transitions are one-way. Once the first surface is added,
|
|
14
|
+
* the turn is in "surface phase" permanently.
|
|
15
|
+
*
|
|
16
|
+
* This prevents "post-surface commentary" features from sneaking in.
|
|
17
|
+
*
|
|
18
|
+
* @see DECISIONS.md ADR-2026-01-022 for design rationale
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import type { AssistantMessagePart, TextPart, SurfacePart } from './types.js'
|
|
22
|
+
|
|
23
|
+
// =============================================================================
|
|
24
|
+
// Builder State
|
|
25
|
+
// =============================================================================
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Immutable state for the part builder.
|
|
29
|
+
* Tracks collected parts and whether surfaces have been added.
|
|
30
|
+
*/
|
|
31
|
+
export interface PartBuilderState {
|
|
32
|
+
/** Collected parts in order */
|
|
33
|
+
readonly parts: readonly AssistantMessagePart[]
|
|
34
|
+
/** Whether any surface part has been added (true = SurfaceState) */
|
|
35
|
+
readonly hasSurface: boolean
|
|
36
|
+
/** Whether dev mode is enabled (throws on invariant violation) */
|
|
37
|
+
readonly devMode: boolean
|
|
38
|
+
/** Count of dropped text parts (for logging) */
|
|
39
|
+
readonly droppedCount: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Result of adding a part to the builder.
|
|
44
|
+
*/
|
|
45
|
+
export interface AddPartResult {
|
|
46
|
+
/** Updated builder state */
|
|
47
|
+
state: PartBuilderState
|
|
48
|
+
/** Whether the part was accepted (false = dropped) */
|
|
49
|
+
accepted: boolean
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// =============================================================================
|
|
53
|
+
// Builder Creation
|
|
54
|
+
// =============================================================================
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Create a new part builder state.
|
|
58
|
+
*
|
|
59
|
+
* @param devMode - If true, throws on invariant violations. If false, silently drops.
|
|
60
|
+
* @returns Initial builder state (NarrativeState)
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* const state = createPartBuilder(process.env.NODE_ENV !== 'production');
|
|
64
|
+
*/
|
|
65
|
+
export function createPartBuilder(devMode = false): PartBuilderState {
|
|
66
|
+
return {
|
|
67
|
+
parts: [],
|
|
68
|
+
hasSurface: false,
|
|
69
|
+
devMode,
|
|
70
|
+
droppedCount: 0,
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// Part Addition
|
|
76
|
+
// =============================================================================
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Add a text part to the builder.
|
|
80
|
+
*
|
|
81
|
+
* INVARIANT: Text parts MUST come before surface parts.
|
|
82
|
+
* - Dev mode: throws Error if text added after surface
|
|
83
|
+
* - Prod mode: silently drops, increments droppedCount
|
|
84
|
+
*
|
|
85
|
+
* @param state - Current builder state
|
|
86
|
+
* @param text - Text content to add
|
|
87
|
+
* @returns Result with updated state and acceptance status
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* let state = createPartBuilder();
|
|
91
|
+
* const result = addText(state, "Hello, world!");
|
|
92
|
+
* state = result.state;
|
|
93
|
+
*/
|
|
94
|
+
export function addText(state: PartBuilderState, text: string): AddPartResult {
|
|
95
|
+
const part: TextPart = { type: 'text', text }
|
|
96
|
+
|
|
97
|
+
if (state.hasSurface) {
|
|
98
|
+
if (state.devMode) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
'PartBuilder invariant violation: text part added after surface part. ' +
|
|
101
|
+
'Narrative content must come before structured surfaces. ' +
|
|
102
|
+
`Parts so far: ${state.parts.length}, dropped: ${state.droppedCount}`
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
// Prod mode: drop silently
|
|
106
|
+
return {
|
|
107
|
+
state: { ...state, droppedCount: state.droppedCount + 1 },
|
|
108
|
+
accepted: false,
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
state: { ...state, parts: [...state.parts, part] },
|
|
114
|
+
accepted: true,
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Add a surface part to the builder.
|
|
120
|
+
*
|
|
121
|
+
* Surface parts mark the transition from NarrativeState to SurfaceState.
|
|
122
|
+
* After a surface is added, subsequent text parts are rejected.
|
|
123
|
+
*
|
|
124
|
+
* @param state - Current builder state
|
|
125
|
+
* @param part - Surface part to add
|
|
126
|
+
* @returns Result with updated state (always accepted)
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* let state = createPartBuilder();
|
|
130
|
+
* state = addSurface(state, { type: 'tool-list', tools: [...] }).state;
|
|
131
|
+
*/
|
|
132
|
+
export function addSurface(
|
|
133
|
+
state: PartBuilderState,
|
|
134
|
+
part: SurfacePart
|
|
135
|
+
): AddPartResult {
|
|
136
|
+
return {
|
|
137
|
+
state: {
|
|
138
|
+
...state,
|
|
139
|
+
parts: [...state.parts, part],
|
|
140
|
+
hasSurface: true,
|
|
141
|
+
},
|
|
142
|
+
accepted: true,
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Add any message part to the builder.
|
|
148
|
+
* Dispatches to addText or addSurface based on part type.
|
|
149
|
+
*
|
|
150
|
+
* @param state - Current builder state
|
|
151
|
+
* @param part - Part to add
|
|
152
|
+
* @returns Result with updated state and acceptance status
|
|
153
|
+
*/
|
|
154
|
+
export function addPart(
|
|
155
|
+
state: PartBuilderState,
|
|
156
|
+
part: AssistantMessagePart
|
|
157
|
+
): AddPartResult {
|
|
158
|
+
if (part.type === 'text') {
|
|
159
|
+
return addText(state, part.text)
|
|
160
|
+
}
|
|
161
|
+
return addSurface(state, part)
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// =============================================================================
|
|
165
|
+
// Builder Finalization
|
|
166
|
+
// =============================================================================
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Extract the final parts array from the builder.
|
|
170
|
+
*
|
|
171
|
+
* @param state - Final builder state
|
|
172
|
+
* @returns Array of message parts in correct order
|
|
173
|
+
*/
|
|
174
|
+
export function buildParts(state: PartBuilderState): AssistantMessagePart[] {
|
|
175
|
+
return [...state.parts]
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Get count of dropped parts (useful for logging/metrics).
|
|
180
|
+
*
|
|
181
|
+
* @param state - Builder state
|
|
182
|
+
* @returns Number of parts dropped due to invariant violations
|
|
183
|
+
*/
|
|
184
|
+
export function getDroppedCount(state: PartBuilderState): number {
|
|
185
|
+
return state.droppedCount
|
|
186
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Parts Barrel
|
|
3
|
+
*
|
|
4
|
+
* Re-exports message part vocabulary types and builder functions.
|
|
5
|
+
* Import from '@company-semantics/contracts' (root).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Types
|
|
9
|
+
export type {
|
|
10
|
+
TextPart,
|
|
11
|
+
ToolListPart,
|
|
12
|
+
StatusPanelPart,
|
|
13
|
+
StatusPanelEntry,
|
|
14
|
+
ChartPart,
|
|
15
|
+
ChartDataPoint,
|
|
16
|
+
TablePart,
|
|
17
|
+
ConfirmationPart,
|
|
18
|
+
SurfacePart,
|
|
19
|
+
AssistantMessagePart,
|
|
20
|
+
} from './types.js'
|
|
21
|
+
|
|
22
|
+
// Type guards
|
|
23
|
+
export { isTextPart, isSurfacePart } from './types.js'
|
|
24
|
+
|
|
25
|
+
// Builder functions
|
|
26
|
+
export type { PartBuilderState, AddPartResult } from './builder.js'
|
|
27
|
+
export {
|
|
28
|
+
createPartBuilder,
|
|
29
|
+
addText,
|
|
30
|
+
addSurface,
|
|
31
|
+
addPart,
|
|
32
|
+
buildParts,
|
|
33
|
+
getDroppedCount,
|
|
34
|
+
} from './builder.js'
|
|
35
|
+
|
|
36
|
+
// Wire format builder
|
|
37
|
+
export { WireSurfaceBuilder } from './wire.js'
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message Parts Vocabulary
|
|
3
|
+
*
|
|
4
|
+
* Canonical types for structured assistant message output.
|
|
5
|
+
* Enables rich UI rendering beyond plain text.
|
|
6
|
+
*
|
|
7
|
+
* INVARIANTS:
|
|
8
|
+
* - Narrative (text) parts MUST come before surface parts
|
|
9
|
+
* - SurfacePart is an extensible union (add new kinds as needed)
|
|
10
|
+
* - TextPart is the ONLY part type that may be streamed char-by-char
|
|
11
|
+
* - Once a surface is added, the turn is in "surface phase" permanently
|
|
12
|
+
*
|
|
13
|
+
* @see DECISIONS.md ADR-2026-01-022 for design rationale
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import type { ToolListMessagePart } from '../mcp/index.js'
|
|
17
|
+
|
|
18
|
+
// =============================================================================
|
|
19
|
+
// Narrative Parts (Streamable)
|
|
20
|
+
// =============================================================================
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Text content part.
|
|
24
|
+
* The only part type that MAY be streamed character-by-character.
|
|
25
|
+
*
|
|
26
|
+
* Design: Aligns with AI SDK's TextPart for interoperability.
|
|
27
|
+
*/
|
|
28
|
+
export interface TextPart {
|
|
29
|
+
type: 'text'
|
|
30
|
+
/** The text content (may be partial during streaming) */
|
|
31
|
+
text: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// =============================================================================
|
|
35
|
+
// Surface Parts (Atomic, Non-Streamable)
|
|
36
|
+
// =============================================================================
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Re-export ToolListMessagePart as ToolListPart for consistency.
|
|
40
|
+
*/
|
|
41
|
+
export type ToolListPart = ToolListMessagePart
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Status panel surface part.
|
|
45
|
+
* Displays system status, connection states, or progress indicators.
|
|
46
|
+
*/
|
|
47
|
+
export interface StatusPanelPart {
|
|
48
|
+
type: 'status-panel'
|
|
49
|
+
/** Panel title */
|
|
50
|
+
title: string
|
|
51
|
+
/** Status entries */
|
|
52
|
+
entries: StatusPanelEntry[]
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Single entry in a status panel.
|
|
57
|
+
*/
|
|
58
|
+
export interface StatusPanelEntry {
|
|
59
|
+
/** Entry label */
|
|
60
|
+
label: string
|
|
61
|
+
/** Current status */
|
|
62
|
+
status: 'ok' | 'warning' | 'error' | 'pending'
|
|
63
|
+
/** Optional detail text */
|
|
64
|
+
detail?: string
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Chart surface part.
|
|
69
|
+
* Renders a data visualization.
|
|
70
|
+
*/
|
|
71
|
+
export interface ChartPart {
|
|
72
|
+
type: 'chart'
|
|
73
|
+
/** Chart type */
|
|
74
|
+
chartType: 'bar' | 'line' | 'pie' | 'area'
|
|
75
|
+
/** Chart title */
|
|
76
|
+
title?: string
|
|
77
|
+
/** Data points */
|
|
78
|
+
data: ChartDataPoint[]
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Single data point for charts.
|
|
83
|
+
*/
|
|
84
|
+
export interface ChartDataPoint {
|
|
85
|
+
label: string
|
|
86
|
+
value: number
|
|
87
|
+
/** Optional color (CSS color string) */
|
|
88
|
+
color?: string
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Table surface part.
|
|
93
|
+
* Renders tabular data.
|
|
94
|
+
*/
|
|
95
|
+
export interface TablePart {
|
|
96
|
+
type: 'table'
|
|
97
|
+
/** Table title */
|
|
98
|
+
title?: string
|
|
99
|
+
/** Column headers */
|
|
100
|
+
headers: string[]
|
|
101
|
+
/** Row data (each row is an array of cell values) */
|
|
102
|
+
rows: string[][]
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Confirmation request surface part.
|
|
107
|
+
* Requests user confirmation before proceeding.
|
|
108
|
+
*/
|
|
109
|
+
export interface ConfirmationPart {
|
|
110
|
+
type: 'confirmation'
|
|
111
|
+
/** What is being confirmed */
|
|
112
|
+
action: string
|
|
113
|
+
/** Optional details */
|
|
114
|
+
details?: string
|
|
115
|
+
/** Confirmation ID for response tracking */
|
|
116
|
+
confirmationId: string
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// =============================================================================
|
|
120
|
+
// Part Unions
|
|
121
|
+
// =============================================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Surface parts are rendered atomically (never streamed).
|
|
125
|
+
* Extensible: add new surface types to this union.
|
|
126
|
+
*/
|
|
127
|
+
export type SurfacePart =
|
|
128
|
+
| ToolListPart
|
|
129
|
+
| StatusPanelPart
|
|
130
|
+
| ChartPart
|
|
131
|
+
| TablePart
|
|
132
|
+
| ConfirmationPart
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* All assistant message part types.
|
|
136
|
+
* Union of narrative (text) and surface parts.
|
|
137
|
+
*/
|
|
138
|
+
export type AssistantMessagePart = TextPart | SurfacePart
|
|
139
|
+
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// Type Guards
|
|
142
|
+
// =============================================================================
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Type guard for TextPart.
|
|
146
|
+
*/
|
|
147
|
+
export function isTextPart(part: AssistantMessagePart): part is TextPart {
|
|
148
|
+
return part.type === 'text'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Type guard for SurfacePart.
|
|
153
|
+
*/
|
|
154
|
+
export function isSurfacePart(part: AssistantMessagePart): part is SurfacePart {
|
|
155
|
+
return part.type !== 'text'
|
|
156
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire Surface Builder
|
|
3
|
+
*
|
|
4
|
+
* Factory functions for creating wire-format surface parts.
|
|
5
|
+
* These follow AI SDK's `data-{name}` convention for custom data parts.
|
|
6
|
+
*
|
|
7
|
+
* Use these in backend code when writing to UIMessageStream.
|
|
8
|
+
* Frontend normalizes wire format to semantic types.
|
|
9
|
+
*
|
|
10
|
+
* @see DECISIONS.md ADR-2026-01-022 for design rationale
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { MCPToolDescriptor, ToolListDataPart } from '../mcp/index.js'
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Factory for creating wire-format surface parts.
|
|
17
|
+
*
|
|
18
|
+
* Wire parts use AI SDK's `data-{name}` type convention.
|
|
19
|
+
* These are transport-level types, not semantic types.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* // In ChatService.ts
|
|
23
|
+
* import { WireSurfaceBuilder } from '@company-semantics/contracts';
|
|
24
|
+
* writer.write(WireSurfaceBuilder.toolList(userTools));
|
|
25
|
+
*/
|
|
26
|
+
export const WireSurfaceBuilder = {
|
|
27
|
+
/**
|
|
28
|
+
* Build a tool-list data part for streaming.
|
|
29
|
+
* Use after LLM text stream completes.
|
|
30
|
+
*
|
|
31
|
+
* @param tools - Array of tool descriptors to include
|
|
32
|
+
* @returns Wire-format tool list part ready for stream
|
|
33
|
+
*/
|
|
34
|
+
toolList(tools: MCPToolDescriptor[]): ToolListDataPart {
|
|
35
|
+
return {
|
|
36
|
+
type: 'data-tool-list',
|
|
37
|
+
data: { tools },
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
} as const
|