or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assistants.mdaudio.mdbatches.mdchat-completions.mdchatkit.mdclient-initialization.mdcompletions.mdcontainers.mdconversations.mdembeddings.mdevals.mdfiles.mdfine-tuning.mdimages.mdindex.mdmodels.mdmoderations.mdrealtime.mdresponses.mdruns.mdthreads-messages.mduploads.mdvector-stores.mdvideos.mdwebhooks.md
KNOWN_ISSUES.md

threads-messages.mddocs/

0

# Threads and Messages

1

2

Create conversational threads and manage messages within the Assistants API. Threads maintain conversation state and messages represent user inputs and assistant responses.

3

4

## Threads

5

6

### Create Thread

7

8

Create a new conversation thread.

9

10

```python { .api }

11

def create(

12

self,

13

*,

14

messages: list[dict] | Omit = omit,

15

metadata: dict[str, str] | Omit = omit,

16

tool_resources: dict | Omit = omit,

17

extra_headers: dict[str, str] | None = None,

18

extra_query: dict[str, object] | None = None,

19

extra_body: dict[str, object] | None = None,

20

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

21

) -> Thread:

22

"""

23

Create a conversation thread.

24

25

Args:

26

messages: Initial messages to add to thread.

27

[{"role": "user", "content": "Hello"}]

28

29

metadata: Key-value pairs (max 16). Keys max 64 chars, values max 512 chars.

30

31

tool_resources: Resources for tools.

32

- {"code_interpreter": {"file_ids": [...]}}

33

- {"file_search": {"vector_store_ids": [...]}}

34

35

extra_headers: Additional HTTP headers.

36

extra_query: Additional query parameters.

37

extra_body: Additional JSON fields.

38

timeout: Request timeout in seconds.

39

40

Returns:

41

Thread: Created thread.

42

"""

43

```

44

45

Usage examples:

46

47

```python

48

from openai import OpenAI

49

50

client = OpenAI()

51

52

# Create empty thread

53

thread = client.beta.threads.create()

54

print(f"Thread ID: {thread.id}")

55

56

# Create with initial messages

57

thread = client.beta.threads.create(

58

messages=[

59

{"role": "user", "content": "Hello!"},

60

{"role": "user", "content": "How are you?"}

61

]

62

)

63

64

# With metadata

65

thread = client.beta.threads.create(

66

metadata={

67

"user_id": "user-123",

68

"session": "abc"

69

}

70

)

71

72

# With tool resources

73

thread = client.beta.threads.create(

74

tool_resources={

75

"file_search": {

76

"vector_store_ids": ["vs_abc123"]

77

}

78

}

79

)

80

```

81

82

### Retrieve Thread

83

84

Get thread details.

85

86

```python { .api }

87

def retrieve(

88

self,

89

thread_id: str,

90

*,

91

extra_headers: dict[str, str] | None = None,

92

extra_query: dict[str, object] | None = None,

93

extra_body: dict[str, object] | None = None,

94

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

95

) -> Thread:

96

"""Get thread details."""

97

```

98

99

### Update Thread

100

101

Modify thread metadata.

102

103

```python { .api }

104

def update(

105

self,

106

thread_id: str,

107

*,

108

metadata: dict[str, str] | Omit = omit,

109

tool_resources: dict | Omit = omit,

110

extra_headers: dict[str, str] | None = None,

111

extra_query: dict[str, object] | None = None,

112

extra_body: dict[str, object] | None = None,

113

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

114

) -> Thread:

115

"""Update thread properties."""

116

```

117

118

### Delete Thread

119

120

Delete a thread.

121

122

```python { .api }

123

def delete(

124

self,

125

thread_id: str,

126

*,

127

extra_headers: dict[str, str] | None = None,

128

extra_query: dict[str, object] | None = None,

129

extra_body: dict[str, object] | None = None,

130

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

131

) -> ThreadDeleted:

132

"""Delete a thread."""

133

```

134

135

### Create and Run

136

137

Create thread and immediately run assistant (convenience method).

138

139

```python { .api }

140

def create_and_run(

141

self,

142

*,

143

assistant_id: str,

144

instructions: str | Omit = omit,

145

metadata: dict[str, str] | Omit = omit,

146

model: str | Omit = omit,

147

thread: dict | Omit = omit,

148

tools: list[dict] | Omit = omit,

149

stream: bool | Omit = omit,

150

temperature: float | Omit = omit,

151

tool_choice: str | dict | Omit = omit,

152

top_p: float | Omit = omit,

153

extra_headers: dict[str, str] | None = None,

154

extra_query: dict[str, object] | None = None,

155

extra_body: dict[str, object] | None = None,

156

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

157

) -> Run:

158

"""

159

Create thread and run assistant in one call.

160

161

Args:

162

assistant_id: The assistant ID.

163

instructions: Override assistant instructions.

164

metadata: Thread metadata.

165

model: Override assistant model.

166

thread: Thread configuration including messages.

167

tools: Override assistant tools.

168

stream: Enable streaming.

169

temperature: Sampling temperature.

170

tool_choice: Tool choice configuration.

171

top_p: Nucleus sampling.

172

173

Returns:

174

Run: Created run.

175

"""

176

```

177

178

Usage example:

179

180

```python

181

# Create thread and run

182

run = client.beta.threads.create_and_run(

183

assistant_id="asst_abc123",

184

thread={

185

"messages": [

186

{"role": "user", "content": "Hello!"}

187

]

188

}

189

)

190

191

print(f"Run ID: {run.id}")

192

print(f"Thread ID: {run.thread_id}")

193

```

194

195

### Create and Run with Polling

196

197

Create a thread, start a run, and automatically poll until the run reaches a terminal state.

198

199

```python { .api }

200

def create_and_run_poll(

201

self,

202

*,

203

assistant_id: str,

204

instructions: str | Omit = omit,

205

max_completion_tokens: int | Omit = omit,

206

max_prompt_tokens: int | Omit = omit,

207

metadata: dict[str, str] | Omit = omit,

208

model: str | Omit = omit,

209

parallel_tool_calls: bool | Omit = omit,

210

response_format: dict | Omit = omit,

211

temperature: float | Omit = omit,

212

thread: dict | Omit = omit,

213

tool_choice: str | dict | Omit = omit,

214

tool_resources: dict | Omit = omit,

215

tools: list[dict] | Omit = omit,

216

top_p: float | Omit = omit,

217

truncation_strategy: dict | Omit = omit,

218

poll_interval_ms: int | Omit = omit,

219

extra_headers: dict[str, str] | None = None,

220

extra_query: dict[str, object] | None = None,

221

extra_body: dict[str, object] | None = None,

222

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

223

) -> Run:

224

"""

225

Create a thread, start a run, and poll for completion.

226

227

Helper method that automatically polls the run until it reaches a terminal state

228

(completed, failed, cancelled, expired). More information on Run lifecycles:

229

https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps

230

231

Args:

232

assistant_id: The assistant ID to run.

233

poll_interval_ms: Polling interval in milliseconds (defaults to 1000ms).

234

thread: Thread configuration including messages.

235

instructions: Override assistant instructions.

236

tools: Override assistant tools.

237

metadata: Thread metadata.

238

(Additional parameters same as create_and_run)

239

240

Returns:

241

Run: Completed run in terminal state.

242

"""

243

```

244

245

Usage example:

246

247

```python

248

# Create and poll automatically

249

run = client.beta.threads.create_and_run_poll(

250

assistant_id="asst_abc123",

251

thread={

252

"messages": [{"role": "user", "content": "Explain quantum computing"}]

253

},

254

poll_interval_ms=500 # Poll every 500ms

255

)

256

257

# Run is guaranteed to be in terminal state

258

print(f"Status: {run.status}") # completed, failed, cancelled, or expired

259

```

260

261

### Create and Run with Streaming

262

263

Create a thread, start a run, and stream the response back in real-time.

264

265

```python { .api }

266

def create_and_run_stream(

267

self,

268

*,

269

assistant_id: str,

270

instructions: str | Omit = omit,

271

max_completion_tokens: int | Omit = omit,

272

max_prompt_tokens: int | Omit = omit,

273

metadata: dict[str, str] | Omit = omit,

274

model: str | Omit = omit,

275

parallel_tool_calls: bool | Omit = omit,

276

response_format: dict | Omit = omit,

277

temperature: float | Omit = omit,

278

thread: dict | Omit = omit,

279

tool_choice: str | dict | Omit = omit,

280

tool_resources: dict | Omit = omit,

281

tools: list[dict] | Omit = omit,

282

top_p: float | Omit = omit,

283

truncation_strategy: dict | Omit = omit,

284

event_handler: AssistantEventHandler | None = None,

285

extra_headers: dict[str, str] | None = None,

286

extra_query: dict[str, object] | None = None,

287

extra_body: dict[str, object] | None = None,

288

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

289

) -> AssistantStreamManager[AssistantEventHandler]:

290

"""

291

Create a thread and stream the run back in real-time.

292

293

Args:

294

assistant_id: The assistant ID to run.

295

event_handler: Optional custom event handler for processing stream events.

296

thread: Thread configuration including messages.

297

instructions: Override assistant instructions.

298

(Additional parameters same as create_and_run)

299

300

Returns:

301

AssistantStreamManager: Stream manager for handling assistant events.

302

"""

303

```

304

305

Usage example:

306

307

```python

308

# Stream with default handler

309

with client.beta.threads.create_and_run_stream(

310

assistant_id="asst_abc123",

311

thread={

312

"messages": [{"role": "user", "content": "Tell me a story"}]

313

}

314

) as stream:

315

for event in stream:

316

if event.event == 'thread.message.delta':

317

print(event.data.delta.content[0].text.value, end='', flush=True)

318

319

# With custom event handler

320

from openai import AssistantEventHandler

321

322

class MyHandler(AssistantEventHandler):

323

def on_text_delta(self, delta, snapshot):

324

print(delta.value, end='', flush=True)

325

326

with client.beta.threads.create_and_run_stream(

327

assistant_id="asst_abc123",

328

thread={

329

"messages": [{"role": "user", "content": "Hello"}]

330

},

331

event_handler=MyHandler()

332

) as stream:

333

stream.until_done()

334

```

335

336

## Messages

337

338

### Create Message

339

340

Add a message to a thread.

341

342

```python { .api }

343

def create(

344

self,

345

thread_id: str,

346

*,

347

role: Literal["user", "assistant"],

348

content: str | list[dict],

349

attachments: list[dict] | Omit = omit,

350

metadata: dict[str, str] | Omit = omit,

351

extra_headers: dict[str, str] | None = None,

352

extra_query: dict[str, object] | None = None,

353

extra_body: dict[str, object] | None = None,

354

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

355

) -> Message:

356

"""

357

Add a message to a thread.

358

359

Args:

360

thread_id: The thread ID.

361

362

role: Message role. "user" or "assistant".

363

364

content: Message content. Can be:

365

- String: "Hello"

366

- List with text/images: [{"type": "text", "text": "..."}, {"type": "image_url", "image_url": {...}}]

367

368

attachments: File attachments with tools.

369

[{"file_id": "file-abc", "tools": [{"type": "code_interpreter"}]}]

370

371

metadata: Key-value pairs.

372

373

Returns:

374

Message: Created message.

375

"""

376

```

377

378

Usage examples:

379

380

```python

381

# Simple text message

382

message = client.beta.threads.messages.create(

383

thread_id="thread_abc123",

384

role="user",

385

content="What is the weather today?"

386

)

387

388

# With attachments

389

message = client.beta.threads.messages.create(

390

thread_id="thread_abc123",

391

role="user",

392

content="Analyze this data",

393

attachments=[

394

{

395

"file_id": "file-abc123",

396

"tools": [{"type": "code_interpreter"}]

397

}

398

]

399

)

400

401

# Multimodal message (text + image)

402

message = client.beta.threads.messages.create(

403

thread_id="thread_abc123",

404

role="user",

405

content=[

406

{"type": "text", "text": "What's in this image?"},

407

{

408

"type": "image_url",

409

"image_url": {"url": "https://example.com/image.jpg"}

410

}

411

]

412

)

413

414

# With metadata

415

message = client.beta.threads.messages.create(

416

thread_id="thread_abc123",

417

role="user",

418

content="Question here",

419

metadata={"source": "web_ui"}

420

)

421

```

422

423

### Retrieve Message

424

425

Get message details.

426

427

```python { .api }

428

def retrieve(

429

self,

430

thread_id: str,

431

message_id: str,

432

*,

433

extra_headers: dict[str, str] | None = None,

434

extra_query: dict[str, object] | None = None,

435

extra_body: dict[str, object] | None = None,

436

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

437

) -> Message:

438

"""Get message details."""

439

```

440

441

### Update Message

442

443

Modify message metadata.

444

445

```python { .api }

446

def update(

447

self,

448

thread_id: str,

449

message_id: str,

450

*,

451

metadata: dict[str, str] | Omit = omit,

452

extra_headers: dict[str, str] | None = None,

453

extra_query: dict[str, object] | None = None,

454

extra_body: dict[str, object] | None = None,

455

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

456

) -> Message:

457

"""Update message metadata."""

458

```

459

460

### List Messages

461

462

List messages in a thread.

463

464

```python { .api }

465

def list(

466

self,

467

thread_id: str,

468

*,

469

after: str | Omit = omit,

470

before: str | Omit = omit,

471

limit: int | Omit = omit,

472

order: Literal["asc", "desc"] | Omit = omit,

473

run_id: str | Omit = omit,

474

extra_headers: dict[str, str] | None = None,

475

extra_query: dict[str, object] | None = None,

476

extra_body: dict[str, object] | None = None,

477

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

478

) -> SyncCursorPage[Message]:

479

"""

480

List messages in a thread.

481

482

Args:

483

thread_id: The thread ID.

484

after: Cursor for next page.

485

before: Cursor for previous page.

486

limit: Number to retrieve (max 100). Default 20.

487

order: Sort order. "asc" or "desc". Default "desc" (newest first).

488

run_id: Filter by run ID.

489

490

Returns:

491

SyncCursorPage[Message]: Paginated messages.

492

"""

493

```

494

495

Usage example:

496

497

```python

498

# List all messages

499

messages = client.beta.threads.messages.list(thread_id="thread_abc123")

500

501

for message in messages:

502

print(f"{message.role}: {message.content[0].text.value}")

503

504

# List in chronological order

505

messages = client.beta.threads.messages.list(

506

thread_id="thread_abc123",

507

order="asc"

508

)

509

510

# Pagination

511

page1 = client.beta.threads.messages.list(thread_id="thread_abc123", limit=10)

512

page2 = client.beta.threads.messages.list(

513

thread_id="thread_abc123",

514

limit=10,

515

after=page1.data[-1].id

516

)

517

```

518

519

### Delete Message

520

521

Delete a message.

522

523

```python { .api }

524

def delete(

525

self,

526

thread_id: str,

527

message_id: str,

528

*,

529

extra_headers: dict[str, str] | None = None,

530

extra_query: dict[str, object] | None = None,

531

extra_body: dict[str, object] | None = None,

532

timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,

533

) -> MessageDeleted:

534

"""Delete a message."""

535

```

536

537

## Types

538

539

```python { .api }

540

from typing import Literal

541

from pydantic import BaseModel

542

543

class Thread(BaseModel):

544

"""Conversation thread."""

545

id: str

546

created_at: int

547

metadata: dict[str, str] | None

548

object: Literal["thread"]

549

tool_resources: dict | None

550

551

class ThreadDeleted(BaseModel):

552

"""Deletion confirmation."""

553

id: str

554

deleted: bool

555

object: Literal["thread.deleted"]

556

557

class Message(BaseModel):

558

"""Thread message."""

559

id: str

560

assistant_id: str | None

561

attachments: list[dict] | None

562

completed_at: int | None

563

content: list[MessageContent]

564

created_at: int

565

incomplete_at: int | None

566

incomplete_details: dict | None

567

metadata: dict[str, str] | None

568

object: Literal["thread.message"]

569

role: Literal["user", "assistant"]

570

run_id: str | None

571

status: Literal["in_progress", "incomplete", "completed"]

572

thread_id: str

573

574

class MessageContent(BaseModel):

575

"""Message content part."""

576

type: Literal["text", "image_file", "image_url"]

577

text: TextContent | None

578

image_file: ImageFile | None

579

image_url: ImageURL | None

580

581

class TextContent(BaseModel):

582

"""Text content."""

583

value: str

584

annotations: list[Annotation]

585

586

class ImageFile(BaseModel):

587

"""Image file reference."""

588

file_id: str

589

detail: Literal["auto", "low", "high"] | None

590

591

class ImageURL(BaseModel):

592

"""Image URL reference."""

593

url: str

594

detail: Literal["auto", "low", "high"] | None

595

596

class Annotation(BaseModel):

597

"""Content annotation (file citation/path)."""

598

type: Literal["file_citation", "file_path"]

599

text: str

600

start_index: int

601

end_index: int

602

file_citation: dict | None

603

file_path: dict | None

604

605

class MessageDeleted(BaseModel):

606

"""Deletion confirmation."""

607

id: str

608

deleted: bool

609

object: Literal["thread.message.deleted"]

610

```

611

612

## Complete Example

613

614

```python

615

from openai import OpenAI

616

617

client = OpenAI()

618

619

# 1. Create assistant

620

assistant = client.beta.assistants.create(

621

name="Helper",

622

model="gpt-4",

623

instructions="You are helpful."

624

)

625

626

# 2. Create thread

627

thread = client.beta.threads.create()

628

629

# 3. Add user message

630

message = client.beta.threads.messages.create(

631

thread_id=thread.id,

632

role="user",

633

content="Tell me a joke"

634

)

635

636

# 4. Run assistant

637

run = client.beta.threads.runs.create(

638

thread_id=thread.id,

639

assistant_id=assistant.id

640

)

641

642

# 5. Wait for completion

643

import time

644

645

while run.status not in ["completed", "failed"]:

646

time.sleep(1)

647

run = client.beta.threads.runs.retrieve(thread_id=thread.id, run_id=run.id)

648

649

# 6. Get messages

650

messages = client.beta.threads.messages.list(thread_id=thread.id)

651

652

for message in messages:

653

role = message.role

654

content = message.content[0].text.value

655

print(f"{role}: {content}")

656

```

657

658

## Async Usage

659

660

```python

661

import asyncio

662

from openai import AsyncOpenAI

663

664

async def create_conversation():

665

client = AsyncOpenAI()

666

667

thread = await client.beta.threads.create()

668

669

message = await client.beta.threads.messages.create(

670

thread_id=thread.id,

671

role="user",

672

content="Hello!"

673

)

674

675

return thread.id, message.id

676

677

thread_id, message_id = asyncio.run(create_conversation())

678

```

679