march-ai-sdk 0.3.0 → 0.4.0
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/README.md +115 -10
- package/dist/{app-C_umwZXh.d.ts → app-Cf_umb8u.d.ts} +49 -51
- package/dist/extensions/langgraph.d.ts +1 -1
- package/dist/extensions/vercel-ai.d.ts +1 -1
- package/dist/index.d.ts +284 -4
- package/dist/index.js +357 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +18 -4
- package/src/streamer.ts +22 -27
- package/src/structural/artifact.ts +97 -0
- package/src/structural/base.ts +83 -0
- package/src/structural/index.ts +12 -0
- package/src/structural/stepper.ts +131 -0
- package/src/structural/surface.ts +93 -0
- package/src/structural/text-block.ts +102 -0
- package/src/artifact.ts +0 -59
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* March Agent SDK - TypeScript framework for building AI agents
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
4
|
* @packageDocumentation
|
|
5
5
|
*/
|
|
6
6
|
|
|
@@ -14,12 +14,26 @@ export { Memory } from './memory.js'
|
|
|
14
14
|
|
|
15
15
|
// Message types
|
|
16
16
|
export { ConversationMessage } from './conversation-message.js'
|
|
17
|
-
|
|
17
|
+
|
|
18
|
+
// Structural streaming components
|
|
19
|
+
export {
|
|
20
|
+
StructuralStreamer,
|
|
21
|
+
Artifact,
|
|
22
|
+
Surface,
|
|
23
|
+
TextBlock,
|
|
24
|
+
Stepper,
|
|
25
|
+
} from './structural/index.js'
|
|
18
26
|
|
|
19
27
|
// Clients
|
|
20
28
|
export { GatewayClient } from './gateway-client.js'
|
|
21
29
|
export { ConversationClient } from './conversation-client.js'
|
|
22
|
-
export {
|
|
30
|
+
export {
|
|
31
|
+
CheckpointClient,
|
|
32
|
+
type CheckpointConfig,
|
|
33
|
+
type CheckpointData,
|
|
34
|
+
type CheckpointMetadata,
|
|
35
|
+
type CheckpointTuple,
|
|
36
|
+
} from './checkpoint-client.js'
|
|
23
37
|
export { AgentStateClient, type AgentStateResponse } from './agent-state-client.js'
|
|
24
38
|
export { MemoryClient } from './memory-client.js'
|
|
25
39
|
export { AttachmentClient, createAttachmentInfo, type AttachmentInfo } from './attachment-client.js'
|
|
@@ -67,4 +81,4 @@ export {
|
|
|
67
81
|
} from './exceptions.js'
|
|
68
82
|
|
|
69
83
|
// Version
|
|
70
|
-
export const VERSION = '0.
|
|
84
|
+
export const VERSION = '0.4.0'
|
package/src/streamer.ts
CHANGED
|
@@ -6,8 +6,7 @@
|
|
|
6
6
|
import type { Message } from './message.js'
|
|
7
7
|
import type { GatewayClient } from './gateway-client.js'
|
|
8
8
|
import type { ConversationClient } from './conversation-client.js'
|
|
9
|
-
import type {
|
|
10
|
-
import { toArtifact } from './artifact.js'
|
|
9
|
+
import type { StructuralStreamer } from './structural/base.js'
|
|
11
10
|
import type { StreamOptions } from './types.js'
|
|
12
11
|
|
|
13
12
|
/**
|
|
@@ -23,9 +22,7 @@ export class Streamer {
|
|
|
23
22
|
|
|
24
23
|
private responseSchema?: Record<string, unknown>
|
|
25
24
|
private messageMetadata?: Record<string, unknown>
|
|
26
|
-
private artifacts: Artifact[] = []
|
|
27
25
|
private streamedContent: string = ''
|
|
28
|
-
private firstChunkSent: boolean = false
|
|
29
26
|
private finished: boolean = false
|
|
30
27
|
|
|
31
28
|
constructor(options: {
|
|
@@ -61,19 +58,22 @@ export class Streamer {
|
|
|
61
58
|
}
|
|
62
59
|
|
|
63
60
|
/**
|
|
64
|
-
*
|
|
61
|
+
* Bind a structural streamer to this streamer for event sending.
|
|
62
|
+
*
|
|
63
|
+
* Returns the structural object itself with streaming capability enabled.
|
|
64
|
+
*
|
|
65
|
+
* @param structural - StructuralStreamer instance (Artifact, Surface, etc.)
|
|
66
|
+
* @returns The same structural object, now bound to this streamer
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* const artifact = new Artifact()
|
|
71
|
+
* s.streamBy(artifact).generating("Creating...")
|
|
72
|
+
* s.streamBy(artifact).done({ url: "...", type: "image" })
|
|
73
|
+
* ```
|
|
65
74
|
*/
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return this
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* Set all artifacts at once (replaces any existing).
|
|
73
|
-
*/
|
|
74
|
-
setArtifacts(artifacts: ArtifactInput[]): this {
|
|
75
|
-
this.artifacts = artifacts.map(toArtifact)
|
|
76
|
-
return this
|
|
75
|
+
streamBy<T extends StructuralStreamer>(structural: T): T {
|
|
76
|
+
return structural._bindStreamer(this)
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/**
|
|
@@ -91,7 +91,7 @@ export class Streamer {
|
|
|
91
91
|
this.streamedContent += content
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
this.
|
|
94
|
+
this._send(content, false, persist, eventType)
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
/**
|
|
@@ -120,7 +120,7 @@ export class Streamer {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
// Send final done message
|
|
123
|
-
this.
|
|
123
|
+
this._send('', true, false)
|
|
124
124
|
|
|
125
125
|
// Set pending response schema on conversation
|
|
126
126
|
if (this.responseSchema && this.conversationClient) {
|
|
@@ -135,8 +135,9 @@ export class Streamer {
|
|
|
135
135
|
|
|
136
136
|
/**
|
|
137
137
|
* Send message to router via gateway.
|
|
138
|
+
* This method is used internally and by structural streamers.
|
|
138
139
|
*/
|
|
139
|
-
|
|
140
|
+
_send(
|
|
140
141
|
content: string,
|
|
141
142
|
done: boolean,
|
|
142
143
|
persist: boolean = true,
|
|
@@ -155,18 +156,12 @@ export class Streamer {
|
|
|
155
156
|
headers.eventType = eventType
|
|
156
157
|
}
|
|
157
158
|
|
|
158
|
-
// Include metadata
|
|
159
|
-
if (!this.
|
|
160
|
-
this.firstChunkSent = true
|
|
161
|
-
|
|
159
|
+
// Include metadata and schema on first chunk (only once)
|
|
160
|
+
if (this.streamedContent.length === 0 && !this.finished) {
|
|
162
161
|
if (this.messageMetadata) {
|
|
163
162
|
headers.messageMetadata = JSON.stringify(this.messageMetadata)
|
|
164
163
|
}
|
|
165
164
|
|
|
166
|
-
if (this.artifacts.length > 0) {
|
|
167
|
-
headers.artifacts = JSON.stringify(this.artifacts)
|
|
168
|
-
}
|
|
169
|
-
|
|
170
165
|
if (this.responseSchema) {
|
|
171
166
|
headers.responseSchema = JSON.stringify(this.responseSchema)
|
|
172
167
|
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - Artifact Structural Streamer
|
|
3
|
+
* Port of Python march_agent/structural/artifact.py
|
|
4
|
+
*
|
|
5
|
+
* Artifact structural streamer for file/image/iframe artifacts.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { StructuralStreamer, generateShortId } from './base.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages artifact lifecycle: generating -> done.
|
|
12
|
+
*
|
|
13
|
+
* Artifacts are files, images, iframes that are generated and displayed.
|
|
14
|
+
* Artifact data is persisted to database on done().
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const artifact = new Artifact() // ID auto-generated
|
|
19
|
+
* s.streamBy(artifact).generating("Creating chart...", 0.5)
|
|
20
|
+
* s.streamBy(artifact).done({
|
|
21
|
+
* url: "https://example.com/chart.png",
|
|
22
|
+
* type: "image",
|
|
23
|
+
* title: "Sales Chart"
|
|
24
|
+
* })
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class Artifact extends StructuralStreamer {
|
|
28
|
+
protected _generateId(): string {
|
|
29
|
+
return `artifact-${generateShortId()}`
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
getEventTypePrefix(): string {
|
|
33
|
+
return 'artifact'
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Signal artifact is being generated.
|
|
38
|
+
*
|
|
39
|
+
* @param message - Status message (e.g., "Creating chart...")
|
|
40
|
+
* @param progress - Progress value 0.0-1.0
|
|
41
|
+
* @returns this for method chaining
|
|
42
|
+
*/
|
|
43
|
+
generating(message?: string, progress?: number): this {
|
|
44
|
+
const data: Record<string, unknown> = {}
|
|
45
|
+
if (message !== undefined) {
|
|
46
|
+
data.message = message
|
|
47
|
+
}
|
|
48
|
+
if (progress !== undefined) {
|
|
49
|
+
data.progress = progress
|
|
50
|
+
}
|
|
51
|
+
return this._sendEvent('generating', data)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Signal artifact is complete and persist to database.
|
|
56
|
+
*
|
|
57
|
+
* @param options - Artifact completion options
|
|
58
|
+
* @param options.url - URL to artifact
|
|
59
|
+
* @param options.type - Artifact type (image, iframe, document, video, audio, code, link, file)
|
|
60
|
+
* @param options.title - Display title
|
|
61
|
+
* @param options.description - Optional description
|
|
62
|
+
* @param options.metadata - Additional metadata (size, mimeType, dimensions, etc.)
|
|
63
|
+
* @returns this for method chaining
|
|
64
|
+
*/
|
|
65
|
+
done(options: {
|
|
66
|
+
url: string
|
|
67
|
+
type: string
|
|
68
|
+
title?: string
|
|
69
|
+
description?: string
|
|
70
|
+
metadata?: Record<string, unknown>
|
|
71
|
+
}): this {
|
|
72
|
+
const data: Record<string, unknown> = {
|
|
73
|
+
url: options.url,
|
|
74
|
+
type: options.type,
|
|
75
|
+
}
|
|
76
|
+
if (options.title) {
|
|
77
|
+
data.title = options.title
|
|
78
|
+
}
|
|
79
|
+
if (options.description) {
|
|
80
|
+
data.description = options.description
|
|
81
|
+
}
|
|
82
|
+
if (options.metadata) {
|
|
83
|
+
data.metadata = options.metadata
|
|
84
|
+
}
|
|
85
|
+
return this._sendEvent('done', data)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Signal artifact generation failed.
|
|
90
|
+
*
|
|
91
|
+
* @param message - Error message
|
|
92
|
+
* @returns this for method chaining
|
|
93
|
+
*/
|
|
94
|
+
error(message: string): this {
|
|
95
|
+
return this._sendEvent('error', { message })
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - Structural Streaming Base
|
|
3
|
+
* Port of Python march_agent/structural/base.py
|
|
4
|
+
*
|
|
5
|
+
* Base class for structural streaming objects.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { Streamer } from '../streamer.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Abstract base class for structural streaming objects.
|
|
12
|
+
*
|
|
13
|
+
* Structural streamers generate events but don't hold streaming state.
|
|
14
|
+
* The Streamer binds to them via streamBy() to enable streaming.
|
|
15
|
+
*/
|
|
16
|
+
export abstract class StructuralStreamer {
|
|
17
|
+
readonly id: string
|
|
18
|
+
protected _streamer?: Streamer
|
|
19
|
+
|
|
20
|
+
constructor(id?: string) {
|
|
21
|
+
this.id = id ?? this._generateId()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generate a unique ID for this streamer type.
|
|
26
|
+
*/
|
|
27
|
+
protected abstract _generateId(): string
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Get the event type prefix (e.g., 'artifact', 'text_block').
|
|
31
|
+
*/
|
|
32
|
+
abstract getEventTypePrefix(): string
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Bind this structural streamer to a Streamer instance.
|
|
36
|
+
* Called by Streamer.streamBy(). Returns self for chaining.
|
|
37
|
+
*/
|
|
38
|
+
_bindStreamer(streamer: Streamer): this {
|
|
39
|
+
this._streamer = streamer
|
|
40
|
+
return this
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Send an event through the bound streamer.
|
|
45
|
+
*
|
|
46
|
+
* Creates event payload and sends via streamer._send().
|
|
47
|
+
* Returns self for method chaining.
|
|
48
|
+
*/
|
|
49
|
+
protected _sendEvent(action: string, data: Record<string, unknown> = {}): this {
|
|
50
|
+
if (!this._streamer) {
|
|
51
|
+
throw new Error(
|
|
52
|
+
`${this.constructor.name} not bound to a Streamer. ` +
|
|
53
|
+
`Call streamer.streamBy() first.`
|
|
54
|
+
)
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Build event body
|
|
58
|
+
const body = { id: this.id, ...data }
|
|
59
|
+
|
|
60
|
+
// Build event type
|
|
61
|
+
const eventType = `${this.getEventTypePrefix()}:${action}`
|
|
62
|
+
|
|
63
|
+
// Send through streamer using existing _send() method
|
|
64
|
+
// content = stringified JSON body
|
|
65
|
+
// eventType = structural event type
|
|
66
|
+
// persist = false (structural events not persisted as content)
|
|
67
|
+
this._streamer._send(
|
|
68
|
+
JSON.stringify(body),
|
|
69
|
+
false, // done
|
|
70
|
+
false, // persist
|
|
71
|
+
eventType
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
return this
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Generate a short random hex string for IDs.
|
|
80
|
+
*/
|
|
81
|
+
export function generateShortId(): string {
|
|
82
|
+
return Math.random().toString(16).slice(2, 10)
|
|
83
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - Structural Streaming Module
|
|
3
|
+
* Port of Python march_agent/structural/__init__.py
|
|
4
|
+
*
|
|
5
|
+
* Exports all structural streaming components.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export { StructuralStreamer, generateShortId } from './base.js'
|
|
9
|
+
export { Artifact } from './artifact.js'
|
|
10
|
+
export { Surface } from './surface.js'
|
|
11
|
+
export { TextBlock } from './text-block.js'
|
|
12
|
+
export { Stepper } from './stepper.js'
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - Stepper Structural Streamer
|
|
3
|
+
* Port of Python march_agent/structural/stepper.py
|
|
4
|
+
*
|
|
5
|
+
* Stepper structural streamer for multi-step progress indicators.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { StructuralStreamer, generateShortId } from './base.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages multi-step progress indicator.
|
|
12
|
+
*
|
|
13
|
+
* Stepper events are NOT persisted to database.
|
|
14
|
+
* IDs are auto-generated - no need to provide them manually.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const stepper = new Stepper({ steps: ["Fetch", "Process", "Report"] }) // ID auto-generated
|
|
19
|
+
* s.streamBy(stepper).startStep(0)
|
|
20
|
+
* s.streamBy(stepper).completeStep(0)
|
|
21
|
+
* s.streamBy(stepper).startStep(1)
|
|
22
|
+
* s.streamBy(stepper).addStep("Verify") // Dynamic step
|
|
23
|
+
* s.streamBy(stepper).completeStep(1)
|
|
24
|
+
* s.streamBy(stepper).done()
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export class Stepper extends StructuralStreamer {
|
|
28
|
+
readonly steps: string[]
|
|
29
|
+
private _initialized: boolean = false
|
|
30
|
+
|
|
31
|
+
constructor(options?: { id?: string; steps?: string[] }) {
|
|
32
|
+
super(options?.id)
|
|
33
|
+
this.steps = options?.steps ?? []
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected _generateId(): string {
|
|
37
|
+
return `stepper-${generateShortId()}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getEventTypePrefix(): string {
|
|
41
|
+
return 'stepper'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Send initialization event with steps if not already sent.
|
|
46
|
+
* This is automatically called before any other stepper event.
|
|
47
|
+
*/
|
|
48
|
+
private _ensureInitialized(): this {
|
|
49
|
+
if (!this._initialized && this.steps.length > 0) {
|
|
50
|
+
this._sendEvent('init', { steps: this.steps })
|
|
51
|
+
this._initialized = true
|
|
52
|
+
}
|
|
53
|
+
return this
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Mark step as in progress.
|
|
58
|
+
*
|
|
59
|
+
* @param index - Step index to start
|
|
60
|
+
* @returns this for method chaining
|
|
61
|
+
*/
|
|
62
|
+
startStep(index: number): this {
|
|
63
|
+
this._ensureInitialized()
|
|
64
|
+
return this._sendEvent('start_step', { index })
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Mark step as complete.
|
|
69
|
+
*
|
|
70
|
+
* @param index - Step index to complete
|
|
71
|
+
* @returns this for method chaining
|
|
72
|
+
*/
|
|
73
|
+
completeStep(index: number): this {
|
|
74
|
+
this._ensureInitialized()
|
|
75
|
+
return this._sendEvent('complete_step', { index })
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Mark step as failed.
|
|
80
|
+
*
|
|
81
|
+
* @param index - Step index that failed
|
|
82
|
+
* @param error - Optional error message
|
|
83
|
+
* @returns this for method chaining
|
|
84
|
+
*/
|
|
85
|
+
failStep(index: number, error?: string): this {
|
|
86
|
+
this._ensureInitialized()
|
|
87
|
+
const data: Record<string, unknown> = { index }
|
|
88
|
+
if (error) {
|
|
89
|
+
data.error = error
|
|
90
|
+
}
|
|
91
|
+
return this._sendEvent('fail_step', data)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Add a new step dynamically.
|
|
96
|
+
*
|
|
97
|
+
* @param label - Step label
|
|
98
|
+
* @param index - Optional position to insert at
|
|
99
|
+
* @returns this for method chaining
|
|
100
|
+
*/
|
|
101
|
+
addStep(label: string, index?: number): this {
|
|
102
|
+
this._ensureInitialized()
|
|
103
|
+
const data: Record<string, unknown> = { label }
|
|
104
|
+
if (index !== undefined) {
|
|
105
|
+
data.index = index
|
|
106
|
+
}
|
|
107
|
+
return this._sendEvent('add_step', data)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Update step label.
|
|
112
|
+
*
|
|
113
|
+
* @param index - Step index to update
|
|
114
|
+
* @param label - New label
|
|
115
|
+
* @returns this for method chaining
|
|
116
|
+
*/
|
|
117
|
+
updateStepLabel(index: number, label: string): this {
|
|
118
|
+
this._ensureInitialized()
|
|
119
|
+
return this._sendEvent('update_step_label', { index, label })
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Mark stepper as complete (all steps finished).
|
|
124
|
+
*
|
|
125
|
+
* @returns this for method chaining
|
|
126
|
+
*/
|
|
127
|
+
done(): this {
|
|
128
|
+
this._ensureInitialized()
|
|
129
|
+
return this._sendEvent('done')
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - Surface Structural Streamer
|
|
3
|
+
* Port of Python march_agent/structural/surface.py
|
|
4
|
+
*
|
|
5
|
+
* Surface structural streamer for embedded interactive components.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { StructuralStreamer, generateShortId } from './base.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages embedded surface lifecycle (similar to Artifact).
|
|
12
|
+
*
|
|
13
|
+
* Surfaces are embedded interactive components (iframes, embeds).
|
|
14
|
+
* Surface data is persisted to database as artifacts with surface type.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const surface = new Surface()
|
|
19
|
+
* s.streamBy(surface).generating("Loading calendar...")
|
|
20
|
+
* s.streamBy(surface).done({ url: "https://cal.com/embed", type: "iframe" })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export class Surface extends StructuralStreamer {
|
|
24
|
+
protected _generateId(): string {
|
|
25
|
+
return `surface-${generateShortId()}`
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
getEventTypePrefix(): string {
|
|
29
|
+
return 'surface'
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Signal surface is loading.
|
|
34
|
+
*
|
|
35
|
+
* @param message - Status message (e.g., "Loading calendar...")
|
|
36
|
+
* @param progress - Progress value 0.0-1.0
|
|
37
|
+
* @returns this for method chaining
|
|
38
|
+
*/
|
|
39
|
+
generating(message?: string, progress?: number): this {
|
|
40
|
+
const data: Record<string, unknown> = {}
|
|
41
|
+
if (message !== undefined) {
|
|
42
|
+
data.message = message
|
|
43
|
+
}
|
|
44
|
+
if (progress !== undefined) {
|
|
45
|
+
data.progress = progress
|
|
46
|
+
}
|
|
47
|
+
return this._sendEvent('generating', data)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Signal surface is ready and persist to database.
|
|
52
|
+
*
|
|
53
|
+
* @param options - Surface completion options
|
|
54
|
+
* @param options.url - URL to surface
|
|
55
|
+
* @param options.type - Surface type (default: iframe)
|
|
56
|
+
* @param options.title - Display title
|
|
57
|
+
* @param options.description - Optional description
|
|
58
|
+
* @param options.metadata - Additional metadata
|
|
59
|
+
* @returns this for method chaining
|
|
60
|
+
*/
|
|
61
|
+
done(options: {
|
|
62
|
+
url: string
|
|
63
|
+
type?: string
|
|
64
|
+
title?: string
|
|
65
|
+
description?: string
|
|
66
|
+
metadata?: Record<string, unknown>
|
|
67
|
+
}): this {
|
|
68
|
+
const data: Record<string, unknown> = {
|
|
69
|
+
url: options.url,
|
|
70
|
+
type: options.type ?? 'iframe',
|
|
71
|
+
}
|
|
72
|
+
if (options.title) {
|
|
73
|
+
data.title = options.title
|
|
74
|
+
}
|
|
75
|
+
if (options.description) {
|
|
76
|
+
data.description = options.description
|
|
77
|
+
}
|
|
78
|
+
if (options.metadata) {
|
|
79
|
+
data.metadata = options.metadata
|
|
80
|
+
}
|
|
81
|
+
return this._sendEvent('done', data)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Signal surface loading failed.
|
|
86
|
+
*
|
|
87
|
+
* @param message - Error message
|
|
88
|
+
* @returns this for method chaining
|
|
89
|
+
*/
|
|
90
|
+
error(message: string): this {
|
|
91
|
+
return this._sendEvent('error', { message })
|
|
92
|
+
}
|
|
93
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* March Agent SDK - TextBlock Structural Streamer
|
|
3
|
+
* Port of Python march_agent/structural/text_block.py
|
|
4
|
+
*
|
|
5
|
+
* TextBlock structural streamer for collapsible text content.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { StructuralStreamer, generateShortId } from './base.js'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Manages collapsible text block with title and body.
|
|
12
|
+
*
|
|
13
|
+
* Both title and body support streaming (append) and update (replace).
|
|
14
|
+
* TextBlock events are NOT persisted to database.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* const block = new TextBlock() // ID auto-generated
|
|
19
|
+
* s.streamBy(block).setVariant("thinking")
|
|
20
|
+
* s.streamBy(block).streamTitle("Deep ")
|
|
21
|
+
* s.streamBy(block).streamTitle("Analysis...")
|
|
22
|
+
* s.streamBy(block).streamBody("Step 1: Check patterns\n")
|
|
23
|
+
* s.streamBy(block).streamBody("Step 2: Validate\n")
|
|
24
|
+
* s.streamBy(block).updateTitle("Analysis Complete")
|
|
25
|
+
* s.streamBy(block).done()
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class TextBlock extends StructuralStreamer {
|
|
29
|
+
readonly initialTitle?: string
|
|
30
|
+
|
|
31
|
+
constructor(options?: { id?: string; title?: string }) {
|
|
32
|
+
super(options?.id)
|
|
33
|
+
this.initialTitle = options?.title
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected _generateId(): string {
|
|
37
|
+
return `text_block-${generateShortId()}`
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
getEventTypePrefix(): string {
|
|
41
|
+
return 'text_block'
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Stream title content (appends to existing).
|
|
46
|
+
*
|
|
47
|
+
* @param content - Content to append to title
|
|
48
|
+
* @returns this for method chaining
|
|
49
|
+
*/
|
|
50
|
+
streamTitle(content: string): this {
|
|
51
|
+
return this._sendEvent('stream_title', { content })
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Stream body content (appends to existing).
|
|
56
|
+
*
|
|
57
|
+
* @param content - Content to append to body
|
|
58
|
+
* @returns this for method chaining
|
|
59
|
+
*/
|
|
60
|
+
streamBody(content: string): this {
|
|
61
|
+
return this._sendEvent('stream_body', { content })
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Replace entire title.
|
|
66
|
+
*
|
|
67
|
+
* @param title - New title (replaces existing)
|
|
68
|
+
* @returns this for method chaining
|
|
69
|
+
*/
|
|
70
|
+
updateTitle(title: string): this {
|
|
71
|
+
return this._sendEvent('update_title', { title })
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Replace entire body.
|
|
76
|
+
*
|
|
77
|
+
* @param body - New body (replaces existing)
|
|
78
|
+
* @returns this for method chaining
|
|
79
|
+
*/
|
|
80
|
+
updateBody(body: string): this {
|
|
81
|
+
return this._sendEvent('update_body', { body })
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Set visual variant.
|
|
86
|
+
*
|
|
87
|
+
* @param variant - Visual style (thinking, note, warning, error, success)
|
|
88
|
+
* @returns this for method chaining
|
|
89
|
+
*/
|
|
90
|
+
setVariant(variant: 'thinking' | 'note' | 'warning' | 'error' | 'success' | string): this {
|
|
91
|
+
return this._sendEvent('set_variant', { variant })
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Mark text block as complete.
|
|
96
|
+
*
|
|
97
|
+
* @returns this for method chaining
|
|
98
|
+
*/
|
|
99
|
+
done(): this {
|
|
100
|
+
return this._sendEvent('done')
|
|
101
|
+
}
|
|
102
|
+
}
|