Build a client in TypeScript using @condensate/agents-sdk. Its methods return Effect values, which describe operations that Effect.runPromise executes. The SDK decodes runtime responses and provides streams for following events.
These examples use the private workspace package inside the Condensate repository. They are runnable files in apps/docs/src/examples and are included in the docs TypeScript check. The website displays their source directly, so the examples and checked files stay together.
1. Configure the client
The client layer provides the runtime's base URL. Save it as client.ts if you are recreating the example in another workspace:
import { Agents, agentsConfigLayer } from "@condensate/agents-sdk"
import { Layer } from "effect"
export const client = Agents.Default.pipe(
Layer.provide(agentsConfigLayer({ baseUrl: "http://127.0.0.1:4741" }))
)
The default local runtime listens on port 4741. Start it with the local setup guide.
2. List the first page of tasks
This read-only example obtains the client, requests up to 20 thread summaries, and prints the pagination metadata:
import { Agents } from "@condensate/agents-sdk"
import { Effect } from "effect"
import { client } from "./client.js"
const page = await Effect.runPromise(
Effect.gen(function* () {
const agents = yield* Agents
return yield* agents.threadPage({ limit: 20 })
}).pipe(Effect.provide(client))
)
console.log(page.threads, page.nextAfter, page.hasMore)
Run the included example from the repository root:
bun apps/docs/src/examples/list.ts
Pass nextAfter back as the next request's after cursor when hasMore is true. Treat the cursor as opaque. Load a selected thread's detail separately so a sidebar does not download every conversation.
3. Follow recorded events
A follower reads after a durable sequence cursor, then waits for more events. This example prints ten events and exits:
import { Agents } from "@condensate/agents-sdk"
import { Effect, Stream } from "effect"
import { client } from "./client.js"
const threadId = process.argv[2]
if (threadId === undefined) throw new Error("Pass an existing thread ID")
await Effect.runPromise(
Effect.gen(function* () {
const agents = yield* Agents
yield* agents.follow(threadId, { after: 0 }).pipe(
Stream.take(10),
Stream.runForEach((event) => Effect.sync(() => console.log(event)))
)
}).pipe(Effect.provide(client))
)
bun apps/docs/src/examples/follow.ts THREAD_ID
Replace THREAD_ID with a real ID. The command can remain open if fewer than ten events arrive; press Ctrl+C to stop it. after: 0 starts from the default beginning, which can use a snapshot shortcut for long histories. Use agents.history(threadId) when you intentionally need the complete history behind snapshots.
For an application, store the last event sequence and use it as after when resuming. The SDK follower handles reconnects and a polling fallback for hosts without the push route.
4. Send work without holding the connection
This example sends a real message to an existing thread. It can start model and tool work under that thread's configuration.
import { Agents } from "@condensate/agents-sdk"
import { Effect } from "effect"
import { client } from "./client.js"
const threadId = process.argv[2]
if (threadId === undefined) throw new Error("Pass an existing thread ID")
const accepted = await Effect.runPromise(
Effect.gen(function* () {
const agents = yield* Agents
return yield* agents.enqueue(threadId, "Summarize the current task and its next step.")
}).pipe(Effect.provide(client))
)
console.log("Message accepted at sequence", accepted.seq)
bun apps/docs/src/examples/send.ts THREAD_ID
enqueue returns when the message is accepted. Follow the log to observe execution. If your caller needs the eventual text response in one request, agents.send(threadId, text) waits for the turn to settle.
Pick the method for your interface
| Method | Use it for |
|---|---|
threadPage({ limit, after }) | A paginated task list |
thread(threadId) | One task's detail |
tail(threadId, { after, limit }) | A bounded event page |
follow(threadId, { after }) | An ongoing durable event stream |
enqueue(threadId, text) | Asynchronous message delivery |
send(threadId, text) | A request that waits for the reply |
For React chat products, also inspect @condensate/chat-sdk and its shared state and rendering components. The HTTP reference explains the routes beneath these operations.