Improve log fetching and Discord command handling

This commit is contained in:
Corey Johnson 2025-07-22 12:10:19 -07:00
parent 8fa8f3a2d3
commit c89a1849a7
5 changed files with 43 additions and 31 deletions

View File

@ -67,7 +67,6 @@ const respond = async (
console.error(`💥 ${content}`, error)
history.push(system(content))
console.log(`🌭 sending`, content)
return content
}
}

View File

@ -12,7 +12,6 @@ import { getLogs } from "../render"
export const runCommand = async (interaction: Interaction<CacheType>) => {
if (!interaction.isChatInputCommand()) return
console.log(`🌭 HI RUNNING`)
const command = commands.find((cmd) => cmd.command.name === interaction.commandName)
ensure(command, `Command ${interaction.commandName} not found`)
@ -33,7 +32,6 @@ export const runCommand = async (interaction: Interaction<CacheType>) => {
export const registerCommands = async (client: Client<boolean>) => {
const commandList = commands.map((cmd) => cmd.command)
console.log(`🌭 Registering commands: ${commandList.map((cmd) => cmd.name).join(", ")}`)
await client.application!.commands.set(commandList)
}
@ -53,34 +51,42 @@ const commands: { command: SlashCommandOptionsOnlyBuilder; execute: ExecuteComma
{ name: "Build", value: "build" },
{ name: "Deploy", value: "deploy" }
)
)
.addNumberOption((option) =>
option
.setName("limit")
.setDescription("The number of logs to fetch (default: 20)")
.setMinValue(3)
.setMaxValue(100)
.setRequired(false)
),
// .addStringOption((option) =>
// option
// .setName("type")
// .setRequired(true)
// .addChoices(
// { name: "App", value: "app" },
// { name: "Build", value: "build" },
// { name: "Deploy", value: "deploy" }
// )
// ),
// .addNumberOption((option) =>
// option
// .setName("limit")
// .setDescription("Number of logs to fetch")
// .setMinValue(1)
// .setMaxValue(100)
// .setRequired(false)
// ),
async execute(interaction) {
console.log(`🌭 in`)
await interaction.deferReply()
console.log(`🌭 out`)
const type = interaction.options.getString("type", true)
const limit = interaction.options.getNumber("limit") ?? undefined
await interaction.editReply(`Fetching ${type} logs...`)
const logs = await getLogs(type as any, limit)
await interaction.editReply(JSON.stringify(logs, null, 2))
if (logs.length === 0) {
await interaction.editReply("No logs found.")
return
} else {
let content = ""
for (const log of [
...logs,
"\nSee all logs at https://dashboard.render.com/web/srv-d1vrdqmuk2gs73eop8o0/logs",
]) {
// Account for the opening/closing ``` in length calculation
if (content.length + log.length >= 1990) {
await interaction.followUp({ content: content, flags: ["SuppressEmbeds"] })
content = log
} else {
content += log + "\n"
}
}
await interaction.followUp({ content: content, flags: ["SuppressEmbeds"] })
}
},
},
]

View File

@ -1,8 +1,13 @@
import { respondToUserMessage } from "../ai"
import { storeEvaluation } from "../eval"
import { ActivityType, type Client } from "discord.js"
import { runCommand } from "./commands"
export const listenForEvents = (client: Client) => {
client.on("interactionCreate", async (interaction) => {
return runCommand(interaction)
})
client.on("messageCreate", async (msg) => {
if (msg.author.bot) return

View File

@ -1,8 +1,9 @@
import { ensure } from "@workshop/shared/utils"
import { bold, time } from "discord.js"
export const getLogs = async (type: "app" | "request" | "build" = "app", limit = 100) => {
const ownerId = "tea-d1vamb95pdvs73d1sgtg"
const resourceId = "srv-d1vrdqmuk2gs73eop8o0"
export const getLogs = async (type: "app" | "request" | "build" = "app", limit = 20) => {
const ownerId = "tea-d1vamb95pdvs73d1sgtg" // owner ID for the Render project (from the render api)
const resourceId = "srv-d1vrdqmuk2gs73eop8o0" // resource ID for the Render service (from the render api)
const url = new URL("https://api.render.com/v1/logs")
url.searchParams.set("type", type)
@ -11,7 +12,6 @@ export const getLogs = async (type: "app" | "request" | "build" = "app", limit =
url.searchParams.set("resource", resourceId)
url.searchParams.set("limit", String(limit))
console.log(`🌭 Fetching logs from Render: ${url.toString()}`)
const response = await fetch(url.toString(), {
method: "GET",
headers: {
@ -26,8 +26,11 @@ export const getLogs = async (type: "app" | "request" | "build" = "app", limit =
const data = (await response.json()) as any
ensure(data.logs, "Expected logs to be an array")
const logs = data.logs.map((log: any) => {
const { id, labels, ...rest } = log
return rest
const { timestamp, message } = log
const unixTimestamp = Math.floor(new Date(timestamp).getTime() / 1000)
const cleanMessage = message.replace(/\x1b\[[0-9;]*m/g, "")
return `${time(unixTimestamp, "t")}: ${cleanMessage}`
})
return logs

View File

@ -21,7 +21,6 @@ export const tools = [
const response = await searchImages(pixabayApiKey, input.imageQuery, { per_page: 10 })
const hit = response.hits[0]!
console.log(`🌭`, `Find the 2d bounding box for this "${input.whereToOverlay}"`)
const image = await Bun.file("public/whiteboard.png").arrayBuffer()
const boundingBox = await getGeminiResponse(
image,