This commit is contained in:
2025-11-23 04:22:25 +01:00
parent 27d2723023
commit 61a3677883
8 changed files with 159 additions and 69 deletions

30
examples/ai/flow_test1.vsh Executable file
View File

@@ -0,0 +1,30 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.ai.client
mut cl := client.new()!
// response := cl.llms.llm_local.chat_completion(
// message: 'Explain quantum computing in simple terms'
// temperature: 0.5
// max_completion_tokens: 1024
// )!
response := cl.llms.llm_maverick.chat_completion(
message: 'Explain quantum computing in simple terms'
temperature: 0.5
max_completion_tokens: 1024
)!
println(response)
// response := cl.llms.llm_embed_local.embed(input: [
// 'The food was delicious and the waiter..',
// ])!
// response2 := cl.llms.llm_embed.embed(input: [
// 'The food was delicious and the waiter..',
// ])!
println(response2)

View File

@@ -5,7 +5,7 @@ import incubaid.herolib.core.flows
type CoordinatorProxy = flows.Coordinator type CoordinatorProxy = flows.Coordinator
pub fn (mut c CoordinatorProxy) start(prompt string) ! { pub fn start(mut c flows.Coordinator, prompt string) ! {
// init the heromodels, define well chosen name, needed to call later // init the heromodels, define well chosen name, needed to call later
mut m := heromodels.new(redis: c.redis, name: 'coordinator_${c.name}')! mut m := heromodels.new(redis: c.redis, name: 'coordinator_${c.name}')!

View File

@@ -10,14 +10,17 @@ import incubaid.herolib.core.logger
import incubaid.herolib.ai.client as aiclient import incubaid.herolib.ai.client as aiclient
import incubaid.herolib.core.redisclient import incubaid.herolib.core.redisclient
import incubaid.herolib.data.paramsparser import incubaid.herolib.data.paramsparser
import incubaid.herolib.core.texttools
@[heap]
pub struct Coordinator { pub struct Coordinator {
pub mut: pub mut:
name string name string
steps map[string]Step current_step string // links to steps dict
logger logger.Logger steps map[string]&Step
ai aiclient.AIClient logger logger.Logger
redis ?&redisclient.Redis ai aiclient.AIClient
redis ?&redisclient.Redis
} }
pub fn new() !Coordinator { pub fn new() !Coordinator {
@@ -41,8 +44,8 @@ pub mut:
} }
// add step to it // add step to it
pub fn (mut c Coordinator) step_new(args StepNewArgs) !Step { pub fn (mut c Coordinator) step_new(args StepNewArgs) !&Step {
return Step{ mut s := Step{
coordinator: &c coordinator: &c
name: args.name name: args.name
description: args.description description: args.description
@@ -52,4 +55,14 @@ pub fn (mut c Coordinator) step_new(args StepNewArgs) !Step {
error: args.error error: args.error
params: args.params params: args.params
} }
s.name = texttools.name_fix(s.name)
c.steps[s.name] = &s
c.current_step = s.name
return &s
}
pub fn (mut c Coordinator) step_current() !&Step {
return c.steps[c.current_step] or {
return error('Current step "${c.current_step}" not found in coordinator "${c.name}"')
}
} }

95
lib/core/flows/run.v Normal file
View File

@@ -0,0 +1,95 @@
module flows
import time as ostime
// Run the entire flow starting from current_step
pub fn (mut c Coordinator) run() ! {
mut s := c.step_current()!
c.run_step(mut s)!
}
// Run a single step, including error and next steps
pub fn (mut c Coordinator) run_step(mut step Step) ! {
// Initialize step
step.status = .running
step.started_at = ostime.now().unix_milli()
step.store_redis()!
// Log step start
step.log(
level: .info
message: 'Step "${step.name}" started'
)!
// Execute main step function
step.main_step(mut step) or {
// Handle error
step.status = .error
step.error_msg = err.msg()
step.finished_at = ostime.now().unix_milli()
step.store_redis()!
step.log(
level: .error
message: 'Step "${step.name}" failed: ${err.msg()}'
)!
// Run error steps if any
if step.error_steps.len > 0 {
for mut error_step in step.error_steps {
c.run_step(mut error_step)!
}
}
return err
}
// Mark as success
step.status = .success
step.finished_at = ostime.now().unix_milli()
step.store_redis()!
step.log(
level: .info
message: 'Step "${step.name}" completed successfully'
)!
// Run next steps if any
if step.next_steps.len > 0 {
for mut next_step in step.next_steps {
c.run_step(mut next_step)!
}
}
}
// Get step state from redis
pub fn (c Coordinator) get_step_state(step_name string) !map[string]string {
if redis := c.redis {
return redis.hgetall('flow:${c.name}:${step_name}')!
}
return error('Redis not configured')
}
// Get all steps state from redis (for UI dashboard)
pub fn (c Coordinator) get_all_steps_state() ![]map[string]string {
mut states := []map[string]string{}
if redis := c.redis {
pattern := 'flow:${c.name}:*'
keys := redis.keys(pattern)!
for key in keys {
state := redis.hgetall(key)!
states << state
}
}
return states
}
pub fn (c Coordinator) clear_redis() ! {
if redis := c.redis {
pattern := 'flow:${c.name}:*'
keys := redis.keys(pattern)!
for key in keys {
redis.del(key)!
}
}
}

View File

@@ -3,8 +3,20 @@ module flows
import incubaid.herolib.data.paramsparser import incubaid.herolib.data.paramsparser
import incubaid.herolib.core.logger import incubaid.herolib.core.logger
pub enum StepStatus {
pending
running
success
error
skipped
}
pub struct Step { pub struct Step {
pub mut: pub mut:
status StepStatus = .pending
started_at i64 // Unix timestamp
finished_at i64
error_msg string
name string name string
description string description string
main_step fn (mut s Step) ! @[required] main_step fn (mut s Step) ! @[required]

View File

@@ -188,15 +188,9 @@ fn test_prd_list() ! {
mut mydb := db.new_test()! mut mydb := db.new_test()!
// Clear the test database to ensure clean state // Clear the test database to ensure clean state
mydb.redis.flushdb()! mydb.redis.flushdb()!
mut db_prd := DBPrd{ mut db_prd := DBPrd{
db: &mydb db: &mydb
} }
// Clear any existing PRDs before running the test
existing_prds := db_prd.list()!
for prd_id in existing_prds {
db_prd.delete[ProductRequirementsDoc](u32(prd_id))!
}
// Create multiple PRDs // Create multiple PRDs
for i in 0 .. 3 { for i in 0 .. 3 {

View File

@@ -1,54 +0,0 @@
module core
// Comment represents a generic commenting functionality that can be associated with any other model
// It supports threaded conversations through parent_comment_id
@[heap]
pub struct Comment {
pub mut:
id u32 // Unique comment ID
user_id u32 // ID of the user who posted the comment (indexed)
content string // The text content of the comment
parent_comment_id ?u32 // Optional parent comment ID for threaded comments
created_at u64 // Creation timestamp
updated_at u64 // Last update timestamp
}
// new creates a new Comment with default values
pub fn Comment.new() Comment {
return Comment{
id: 0
user_id: 0
content: ''
parent_comment_id: none
created_at: 0
updated_at: 0
}
}
// user_id sets the user ID for the comment (builder pattern)
pub fn (mut c Comment) user_id(id u32) Comment {
c.user_id = id
return c
}
// content sets the content for the comment (builder pattern)
pub fn (mut c Comment) content(text string) Comment {
c.content = text
return c
}
// parent_comment_id sets the parent comment ID for threaded comments (builder pattern)
pub fn (mut c Comment) parent_comment_id(parent_id ?u32) Comment {
c.parent_comment_id = parent_id
return c
}
// is_top_level returns true if this is a top-level comment (no parent)
pub fn (c Comment) is_top_level() bool {
return c.parent_comment_id == none
}
// is_reply returns true if this is a reply to another comment
pub fn (c Comment) is_reply() bool {
return c.parent_comment_id != none
}

View File

@@ -1,4 +1,4 @@
module flow module flow
// Flow represents a signing flow // Flow represents a signing flow
@[heap] @[heap]