slackline/stream
Stream a reply into Slack while an agent writes it. You say what the reply should show right now, and this module works out which calls to make.
import slackline/stream
import slackline/stream/httpc as reply
let assert Ok(r) =
stream.new(client, channel: "C123")
|> stream.in_thread("1700000000.000100")
|> stream.to(user: "U123", team: "T123")
|> reply.open
reply.text(r, "Looking at the failing test")
reply.task(r, stream.Task("t1", "Run the tests", stream.Running, "", ""))
reply.text(r, "Looking at the failing test. It races the clock.")
reply.task(r, stream.Task("t1", "Run the tests", stream.Done, "", "24 passed"))
let assert Ok(finished) = reply.finish(r, closing: "Changed 1 file")
Pass text the whole reply so far, not just the new part. Slack keeps a
streamed message open for ten minutes and lets it hold 12,000 characters
and 50 tasks. When a message fills up or runs out of time, the reply
continues in a new message and the session stays marked as working. If
you rewrite text after it has streamed, the new version is posted when
the reply finishes. If Slack won’t stream, the reply falls back to a plan
card and plain messages.
This module holds the code both targets share. That is the builder, the
rules, and the API calls the rules ask for. The rules are pure. Use
stream/httpc to run a reply on Erlang and stream/fetch to run one on
JavaScript.
Types
Says where a reply goes and how often it updates. Open it with
stream/httpc on Erlang or stream/fetch on JavaScript.
pub opaque type Builder
The result of a finished reply. messages lists the ts of every message
it posted, oldest first. streamed is False if the reply fell back to
plain messages, and problem says why.
pub type Finished {
Finished(
messages: List(String),
streamed: Bool,
problem: option.Option(String),
)
}
Constructors
-
Finished( messages: List(String), streamed: Bool, problem: option.Option(String), )
How much a streamed message can hold and how long it stays open, in
milliseconds. slack_limits stays a little under Slack’s own limits of
12,000 characters, 50 tasks and ten minutes.
pub type Limits {
Limits(text: Int, tasks: Int, life_ms: Int)
}
Constructors
-
Limits(text: Int, tasks: Int, life_ms: Int)
pub type Next {
Wait
Do(
step: Step,
answer: fn(Result(String, slackline.Error)) -> Answer,
)
Over
}
Constructors
-
WaitThere is nothing to send yet.
-
Do( step: Step, answer: fn(Result(String, slackline.Error)) -> Answer, )Make
step, then pass its outcome toanswer. -
OverThe reply is done.
The result of a call. On success it holds the ts of the message the call posted, or “” if it posted none.
pub type Outcome =
Result(String, slackline.Error)
Tracks what Slack has been shown of a reply. The rules are pure. Call
next_step to get the next call, make it, then pass the outcome to its
answer.
pub opaque type Rules
A call to Slack that the rules want made.
pub type Step {
Start(chunks: List(chat.StreamChunk))
Append(ts: String, chunks: List(chat.StreamChunk))
Stop(
ts: String,
chunks: List(chat.StreamChunk),
carry_on: Bool,
)
Post(text: String)
PostPlan(title: String, tasks: List(Task))
UpdatePlan(ts: String, title: String, tasks: List(Task))
}
Constructors
-
Start(chunks: List(chat.StreamChunk)) -
Append(ts: String, chunks: List(chat.StreamChunk)) -
Stop(ts: String, chunks: List(chat.StreamChunk), carry_on: Bool)carry_onis True when the reply will continue in a new message. Slack then keeps showing the session as working. -
Post(text: String) -
PostPlan(title: String, tasks: List(Task)) -
UpdatePlan(ts: String, title: String, tasks: List(Task))
A step of the work, shown in the reply’s plan. A task with the same id
replaces an earlier one. Set details or output to “” to leave it out.
pub type Task {
Task(
id: String,
title: String,
status: Status,
details: String,
output: String,
)
}
Constructors
-
Task( id: String, title: String, status: Status, details: String, output: String, )
Values
pub const calls_per_flush: Int
How many calls a driver makes in one go before it pauses and lets updates collect again.
pub fn closing(rules: Rules, closing: String) -> Rules
Marks the reply as finishing. closing is a last line to add at the
end, or “” for none.
pub fn every(builder: Builder, milliseconds: Int) -> Builder
Sends updates at most once every milliseconds. The default is 1000.
pub fn new(
client: slackline.Client,
channel channel: String,
) -> Builder
Starts a reply in channel. For a reply in a channel thread, also call
in_thread and to. For a reply at the top level of a code channel or a
DM, call only to.
pub fn next_step(rules: Rules, shows: Shows, now_ms: Int) -> Next
Returns the next call to make, given what the reply shows and the current time in milliseconds.
pub const slack_limits: Limits