Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.brightinventions.koog
package pl.brightinventions.koog.agent

import io.ktor.client.HttpClient
import io.ktor.client.call.body
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.brightinventions.koog
package pl.brightinventions.koog.agent

import ai.koog.agents.core.agent.AIAgent
import ai.koog.agents.core.tools.ToolRegistry
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.brightinventions.koog
package pl.brightinventions.koog.agent

import io.ktor.client.HttpClient
import io.ktor.client.request.header
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package pl.brightinventions.koog
package pl.brightinventions.koog.agent

import ai.koog.agents.core.tools.annotations.LLMDescription
import ai.koog.agents.core.tools.annotations.Tool
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package pl.brightinventions.koog.financial.news.monitor

import ai.koog.agents.core.tools.Tool.Args
import kotlinx.serialization.Serializable

@Serializable
data class Article(
val title: String,
val summary: String,
val author: String,
val source: String,
val url: String,
) : Args {

override fun toString(): String {
return "$title by $author, source: $source, URL: $url\nSummary: $summary"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package pl.brightinventions.koog.financial.news.monitor

import ai.koog.agents.core.tools.SimpleTool
import ai.koog.agents.core.tools.ToolDescriptor
import kotlinx.serialization.KSerializer

class ArticleTool : SimpleTool<Article>() {

override suspend fun doExecute(args: Article): String {
return args.toString()
}

override val argsSerializer: KSerializer<Article> = Article.serializer()

override val descriptor: ToolDescriptor = ToolDescriptor(
name = "articleTool",
description = "A tool to parse book information from markdown",
requiredParameters = listOf(),
optionalParameters = listOf()
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package pl.brightinventions.koog.financial.news.monitor

import ai.koog.agents.core.agent.AIAgent
import ai.koog.agents.core.agent.config.AIAgentConfig
import ai.koog.agents.core.dsl.builder.forwardTo
import ai.koog.agents.core.dsl.builder.strategy
import ai.koog.agents.core.tools.ToolRegistry
import ai.koog.prompt.executor.llms.all.simpleOpenAIExecutor
import kotlinx.coroutines.runBlocking

fun main() {
val agentStrategy = strategy("articles-assistant") {
val getMdOutput by node<String, String> { input ->
val mdDefinition = markdownArticleDefinition()

llm.writeSession {
updatePrompt { user(input) }
val markdownStream = requestLLMStreaming(mdDefinition)

parseMarkdownStreamToArticles(markdownStream)
.collect { article ->
callTool<ArticleTool>(article)
}
}

""
}

edge(nodeStart forwardTo getMdOutput)
edge(getMdOutput forwardTo nodeFinish)
}


val agent = AIAgent(
promptExecutor = simpleOpenAIExecutor(System.getenv("OPENAI_API_KEY")),
strategy = agentStrategy,
agentConfig = AIAgentConfig.withSystemPrompt(
prompt = """
You're AI financial news assistant. Please provide users with comprehensive and structured information about the financial news of the world.
""".trimIndent()
),
toolRegistry = ToolRegistry {
tool(ArticleTool())
},
)

val command = """
Provide me latest financial news.
""".trimIndent()

runBlocking { agent.run(command) }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package pl.brightinventions.koog.financial.news.monitor

import ai.koog.prompt.markdown.markdown
import ai.koog.prompt.structure.markdown.MarkdownStructuredDataDefinition

fun markdownArticleDefinition(): MarkdownStructuredDataDefinition {
return MarkdownStructuredDataDefinition("articlesList", schema = {
markdown {
header(1, "articleTitle")
bulleted {
item("summary")
item("author")
item("source")
item("url")
}
}
}, examples = {
markdown {
header(1, "CocaCola stock is reaching all time high!")
bulleted {
item("CocaCola's stock has reached an all-time high, driven by strong quarterly earnings and increased consumer demand.")
item("John Doe")
item("Financial News Daily")
item("https://financialnewsdaily.com/coca-cola-stock-high")
}
}
})
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package pl.brightinventions.koog.financial.news.monitor

import ai.koog.prompt.structure.markdown.markdownStreamingParser
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow

fun parseMarkdownStreamToArticles(markdownStream: Flow<String>): Flow<Article> {
return flow {
markdownStreamingParser {
var currentArticleTitle = ""
val bulletPoints = mutableListOf<String>()

onHeader(1) { headerText ->
if (currentArticleTitle.isNotEmpty() && bulletPoints.isNotEmpty()) {
mapAndEmit(bulletPoints, currentArticleTitle)
}

currentArticleTitle = headerText
bulletPoints.clear()
}

onBullet { bulletText ->
bulletPoints.add(bulletText)
}

onFinishStream {
if (currentArticleTitle.isNotEmpty() && bulletPoints.isNotEmpty()) {
mapAndEmit(bulletPoints, currentArticleTitle)
}
}
}.parseStream(markdownStream)
}
}

private suspend fun FlowCollector<Article>.mapAndEmit(
bulletPoints: List<String>,
currentArticleTitle: String
) {
val summary = bulletPoints.getOrNull(0) ?: ""
val author = bulletPoints.getOrNull(1) ?: ""
val source = bulletPoints.getOrNull(2) ?: ""
val url = bulletPoints.getOrNull(3) ?: ""

emit(
Article(
title = currentArticleTitle,
summary = summary,
author = author,
source = source,
url = url
)
)
}