feat: add robust LLM JSON parser and fix Group Chat schema (#388)

Add robust LLM JSON parsing utilities to handle unreliable model output:
- Parse tool arguments with tolerance for Python format (single quotes, trailing commas)
- Extract text from Anthropic-style content arrays in streaming events
- Normalize tool_result content to string format per Hermes spec
- Parse message.delta and run.completed output to avoid displaying JSON strings

Fix Group Chat database schema errors:
- Add id column as PRIMARY KEY to gc_room_agents and gc_room_members tables
- Change from composite primary keys to single-column id keys
- Update tests to match new schema structure

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
ekko
2026-05-02 08:58:14 +08:00
committed by GitHub
parent 9325aa5482
commit 969c7c0e1a
5 changed files with 457 additions and 135 deletions
+3 -3
View File
@@ -119,6 +119,7 @@ export const GC_MESSAGES_SCHEMA: Record<string, string> = {
export const GC_ROOM_AGENTS_TABLE = 'gc_room_agents'
export const GC_ROOM_AGENTS_SCHEMA: Record<string, string> = {
id: 'TEXT PRIMARY KEY',
roomId: 'TEXT NOT NULL',
agentId: 'TEXT NOT NULL',
profile: 'TEXT NOT NULL',
@@ -140,6 +141,7 @@ export const GC_CONTEXT_SNAPSHOTS_SCHEMA: Record<string, string> = {
export const GC_ROOM_MEMBERS_TABLE = 'gc_room_members'
export const GC_ROOM_MEMBERS_SCHEMA: Record<string, string> = {
id: 'TEXT PRIMARY KEY',
roomId: 'TEXT NOT NULL',
userId: 'TEXT NOT NULL',
userName: 'TEXT NOT NULL',
@@ -474,16 +476,14 @@ export function initAllHermesTables(retryCount = 0): void {
syncTable(GC_PENDING_SESSION_DELETES_TABLE, GC_PENDING_SESSION_DELETES_SCHEMA)
syncTable(GC_SESSION_PROFILES_TABLE, GC_SESSION_PROFILES_SCHEMA)
// Group chat - composite primary key tables
// Group chat - single-column primary key tables (PRIMARY KEY in column definition)
syncTable(GC_ROOM_AGENTS_TABLE, GC_ROOM_AGENTS_SCHEMA, {
primaryKey: 'roomId, agentId',
indexes: {
idx_gc_room_agents_profile: 'CREATE INDEX idx_gc_room_agents_profile ON gc_room_agents(profile)',
}
})
syncTable(GC_ROOM_MEMBERS_TABLE, GC_ROOM_MEMBERS_SCHEMA, {
primaryKey: 'roomId, userId',
indexes: {
idx_gc_room_members_user: 'CREATE INDEX idx_gc_room_members_user ON gc_room_members(userId)',
}