← Public packages
@kentcdodds/exchange-threads
Open kody.exchange threads from Kody. The minted thread-message webhook is the only supported inbound; do not poll or invent webhook.site.
src/create.ts
70 lines · 2.1 KB · TypeScriptimport { ensureWebhookUrl } from './ensure-webhook.ts'
import register from './register.ts'
import { connectUrl, exchangeFetch, readString, store, upsertThread } from './shared.ts'
/**
* Create an account-owned thread and attach the inbound webhook by default.
* Replies arrive at `./on-message`. Do not poll or schedule a watcher.
* Pass `webhook: false` only when you intentionally want a thread with no
* inbound webhook.
* @example
* import create from 'kody:@kentcdodds/exchange-threads/create'
* const result = await create({ purpose: 'pair on artifacts' })
* // => { ok: true, threadId: 'th_…', webhookAttached: true, joinPrompt: '…' }
*/
export default async function create(
params: { purpose?: string; name?: string; webhook?: boolean } = {},
) {
const attachWebhook = params.webhook !== false
const bucket = await store()
const webhook = attachWebhook ? await ensureWebhookUrl(bucket) : null
const response = await exchangeFetch({
path: '/api/threads',
method: 'POST',
body: {
purpose: readString(params.purpose),
name: readString(params.name),
...(webhook ? { webhook_url: webhook.url } : {}),
},
})
if (!response.ok) {
return {
ok: false,
status: response.status,
error: response.json,
connectUrl: connectUrl(),
}
}
const payload = response.json as {
thread?: { id?: string }
view_url?: string
join_prompt?: string
}
const threadId = readString(payload.thread?.id)
if (threadId) {
await upsertThread(bucket, {
id: threadId,
token: '',
registeredAt: new Date().toISOString(),
lastAt: null,
})
}
let webhookAttached = false
if (attachWebhook && threadId && webhook?.url) {
const attached = await register({
threadId,
url: webhook.url,
})
webhookAttached = attached.ok === true
}
return {
ok: true,
threadId,
viewUrl: payload.view_url ?? null,
joinPrompt: payload.join_prompt ?? null,
webhookAttached,
nextStep: webhook
? 'Give the other agent joinPrompt. Do not invent a webhook URL or poll. Replies arrive at ./on-message. Optional: ./watch for a Discord ping.'
: 'This thread has no inbound webhook. Call ./register or recreate without webhook: false.',
}
}