From d4af26e59d344a333f2353eeefe48093673fe54c Mon Sep 17 00:00:00 2001 From: Jonas Pacheco Date: Thu, 26 Mar 2026 16:26:43 -0300 Subject: [PATCH] fix(miroflow): fallback robusto para resultado do agente + modelo llama3.2:3b MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - miroflow_service.py: extrai resposta de summary, final_boxed_answer, exceed_max_turn_summary ou último message_history do assistente - Troca deepseek-r1:14b por llama3.2:3b nos agentes Statistician e Fiscal Auditor - shared/schema.ts: adiciona tabelas OpenClaw (detectedPatterns, skillSuggestions) Co-Authored-By: Claude Sonnet 4.6 --- server/python/miroflow_service.py | 18 +++++++-- shared/schema.ts | 64 +++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 3 deletions(-) diff --git a/server/python/miroflow_service.py b/server/python/miroflow_service.py index a8daf64..9d13ee4 100644 --- a/server/python/miroflow_service.py +++ b/server/python/miroflow_service.py @@ -25,8 +25,8 @@ OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://localhost:11434") RESEARCHER_MODEL = os.getenv("MIROFLOW_RESEARCHER_MODEL", "llama3.1:8b") AGENT_MODELS = { - "statistician": "deepseek-r1:14b", - "fiscal_auditor": "deepseek-r1:14b", + "statistician": "llama3.2:3b", + "fiscal_auditor": "llama3.2:3b", "researcher": RESEARCHER_MODEL, } @@ -75,7 +75,19 @@ async def run_agent(agent_type: str, task: str) -> tuple[str, str]: initial_user_message=task, ) result = await agent.run(ctx) - text = result.get("summary", str(result)) if isinstance(result, dict) else str(result) + if isinstance(result, dict): + text = ( + result.get("summary") + or result.get("final_boxed_answer") + or result.get("exceed_max_turn_summary") + or next( + (m["content"] for m in reversed(result.get("message_history") or []) if m.get("role") == "assistant"), + None, + ) + or str(result) + ) + else: + text = str(result) return text, cfg["llm"]["model_name"] diff --git a/shared/schema.ts b/shared/schema.ts index fed0c83..a005604 100644 --- a/shared/schema.ts +++ b/shared/schema.ts @@ -7525,3 +7525,67 @@ export type ArcadiaSkill = typeof arcadiaSkills.$inferSelect; export type InsertArcadiaSkill = z.infer; export type SkillExecution = typeof skillExecutions.$inferSelect; export type InsertSkillExecution = z.infer; + +// ============================================================ +// OpenClaw — Fase 4: Detecção de Padrões e Emergência de Skills +// ============================================================ + +export const detectedPatterns = pgTable("detected_patterns", { + id: uuid("id").primaryKey().defaultRandom(), + tenantId: integer("tenant_id").references(() => tenants.id), + userId: varchar("user_id").references(() => users.id), + + // Padrão detectado + actionType: varchar("action_type", { length: 100 }).notNull(), + description: text("description"), + frequency: integer("frequency").notNull().default(0), + confidence: numeric("confidence", { precision: 4, scale: 3 }).notNull().default("0"), + + // Janela de análise + firstSeenAt: timestamp("first_seen_at").default(sql`CURRENT_TIMESTAMP`).notNull(), + lastSeenAt: timestamp("last_seen_at").default(sql`CURRENT_TIMESTAMP`).notNull(), + + // Metadados do padrão (contexto, módulos envolvidos, etc.) + metadata: jsonb("metadata").default({}), + + // Estado do ciclo de vida + status: varchar("status", { length: 20 }).notNull().default("active"), // active | archived | converted + + createdAt: timestamp("created_at").default(sql`CURRENT_TIMESTAMP`).notNull(), + updatedAt: timestamp("updated_at").default(sql`CURRENT_TIMESTAMP`).notNull(), +}); + +export const skillSuggestions = pgTable("skill_suggestions", { + id: uuid("id").primaryKey().defaultRandom(), + patternId: uuid("pattern_id").references(() => detectedPatterns.id, { onDelete: "cascade" }), + tenantId: integer("tenant_id").references(() => tenants.id), + userId: varchar("user_id").references(() => users.id), + + // Skill sugerida + suggestedSkillName: varchar("suggested_skill_name", { length: 200 }).notNull(), + suggestedDescription: text("suggested_description"), + estimatedAutomation: text("estimated_automation"), + confidence: numeric("confidence", { precision: 4, scale: 3 }).notNull().default("0"), + + // Skill gerada (após confirmação) + generatedSkillId: uuid("generated_skill_id").references(() => arcadiaSkills.id), + + // Estado da sugestão + status: varchar("status", { length: 20 }).notNull().default("pending"), // pending | accepted | rejected | expired + + // Rastreabilidade + source: varchar("source", { length: 50 }).notNull().default("openclaw"), + reviewedBy: varchar("reviewed_by").references(() => users.id), + reviewedAt: timestamp("reviewed_at"), + + createdAt: timestamp("created_at").default(sql`CURRENT_TIMESTAMP`).notNull(), + updatedAt: timestamp("updated_at").default(sql`CURRENT_TIMESTAMP`).notNull(), +}); + +export const insertDetectedPatternSchema = createInsertSchema(detectedPatterns).omit({ id: true, createdAt: true, updatedAt: true }); +export const insertSkillSuggestionSchema = createInsertSchema(skillSuggestions).omit({ id: true, createdAt: true, updatedAt: true }); + +export type DetectedPattern = typeof detectedPatterns.$inferSelect; +export type InsertDetectedPattern = z.infer; +export type SkillSuggestionRecord = typeof skillSuggestions.$inferSelect; +export type InsertSkillSuggestion = z.infer;