Skip to content

Commit 0379cf1

Browse files
authored
Harden SME chat and gateway flow (#366)
- Simplify SME message persistence and UI wiring - Tighten OpenClaw gateway test handling and result rendering - Update v0.19.0 release notes
1 parent d2a5e43 commit 0379cf1

8 files changed

Lines changed: 223 additions & 278 deletions

File tree

apps/server/src/persistence/Layers/SmeMessages.ts

Lines changed: 44 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,13 @@
11
import * as SqlClient from "effect/unstable/sql/SqlClient";
2-
import * as SqlSchema from "effect/unstable/sql/SqlSchema";
3-
import { Effect, Layer, Schema } from "effect";
4-
5-
import { toPersistenceDecodeError, toPersistenceSqlError } from "../Errors.ts";
2+
import { Effect, Layer } from "effect";
3+
import { toPersistenceSqlError } from "../Errors.ts";
64

75
import {
8-
DeleteSmeMessagesByConversationInput,
9-
ListSmeMessagesByConversationInput,
106
SmeMessageRepository,
11-
SmeMessageRow,
127
type SmeMessageRepositoryShape,
8+
type SmeMessageRow,
139
} from "../Services/SmeMessages.ts";
1410

15-
function toPersistenceSqlOrDecodeError(sqlOperation: string, decodeOperation: string) {
16-
return (cause: unknown) =>
17-
Schema.isSchemaError(cause)
18-
? toPersistenceDecodeError(decodeOperation)(cause)
19-
: toPersistenceSqlError(sqlOperation)(cause);
20-
}
21-
22-
/**
23-
* DB row schema: isStreaming stored as INTEGER 0/1, mapped to/from boolean.
24-
*/
25-
const SmeMessageDbRow = Schema.Struct({
26-
messageId: SmeMessageRow.fields.messageId,
27-
conversationId: SmeMessageRow.fields.conversationId,
28-
role: SmeMessageRow.fields.role,
29-
text: SmeMessageRow.fields.text,
30-
isStreaming: Schema.Number,
31-
createdAt: SmeMessageRow.fields.createdAt,
32-
updatedAt: SmeMessageRow.fields.updatedAt,
33-
});
34-
3511
const makeSmeMessageRepository = Effect.gen(function* () {
3612
const sql = yield* SqlClient.SqlClient;
3713

@@ -56,40 +32,51 @@ const makeSmeMessageRepository = Effect.gen(function* () {
5632
}).pipe(Effect.mapError(toPersistenceSqlError("SmeMessageRepository.upsert:query")));
5733

5834
const listByConversationId: SmeMessageRepositoryShape["listByConversationId"] = (input) =>
59-
Effect.gen(function* () {
60-
const rows = yield* sql`
61-
SELECT
62-
message_id AS "messageId",
63-
conversation_id AS "conversationId",
64-
role,
65-
text,
66-
is_streaming AS "isStreaming",
67-
created_at AS "createdAt",
68-
updated_at AS "updatedAt"
69-
FROM sme_messages
70-
WHERE conversation_id = ${input.conversationId}
71-
ORDER BY created_at ASC
72-
`;
73-
return rows.map((r: any) => ({
74-
messageId: r.messageId,
75-
conversationId: r.conversationId,
76-
role: r.role,
77-
text: r.text,
78-
isStreaming: r.isStreaming !== 0,
79-
createdAt: r.createdAt,
80-
updatedAt: r.updatedAt,
81-
})) as any;
82-
}).pipe(
35+
sql`
36+
SELECT
37+
message_id AS "messageId",
38+
conversation_id AS "conversationId",
39+
role,
40+
text,
41+
is_streaming AS "isStreaming",
42+
created_at AS "createdAt",
43+
updated_at AS "updatedAt"
44+
FROM sme_messages
45+
WHERE conversation_id = ${input.conversationId}
46+
ORDER BY created_at ASC
47+
`.pipe(
48+
Effect.map((rows) =>
49+
(
50+
rows as ReadonlyArray<{
51+
messageId: string;
52+
conversationId: string;
53+
role: string;
54+
text: string;
55+
isStreaming: number;
56+
createdAt: string;
57+
updatedAt: string;
58+
}>
59+
).map(
60+
(r) =>
61+
({
62+
messageId: r.messageId as SmeMessageRow["messageId"],
63+
conversationId: r.conversationId as SmeMessageRow["conversationId"],
64+
role: r.role,
65+
text: r.text,
66+
isStreaming: r.isStreaming !== 0,
67+
createdAt: r.createdAt,
68+
updatedAt: r.updatedAt,
69+
}) as SmeMessageRow,
70+
),
71+
),
8372
Effect.mapError(toPersistenceSqlError("SmeMessageRepository.listByConversationId:query")),
8473
);
8574

8675
const deleteByConversationId: SmeMessageRepositoryShape["deleteByConversationId"] = (input) =>
87-
Effect.gen(function* () {
88-
yield* sql`
89-
DELETE FROM sme_messages
90-
WHERE conversation_id = ${input.conversationId}
91-
`;
92-
}).pipe(
76+
sql`
77+
DELETE FROM sme_messages
78+
WHERE conversation_id = ${input.conversationId}
79+
`.pipe(
9380
Effect.mapError(toPersistenceSqlError("SmeMessageRepository.deleteByConversationId:query")),
9481
);
9582

apps/server/src/sme/Layers/SmeChatServiceLive.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,13 @@
77
* @module SmeChatServiceLive
88
*/
99
import Anthropic from "@anthropic-ai/sdk";
10-
import type {
11-
SmeConversation,
12-
SmeKnowledgeDocument,
13-
SmeMessage,
14-
SmeMessageEvent,
15-
} from "@okcode/contracts";
10+
import type { SmeConversation, SmeKnowledgeDocument, SmeMessage } from "@okcode/contracts";
1611
import {
1712
SME_MAX_DOCUMENT_SIZE_BYTES,
1813
SME_MAX_DOCUMENTS_PER_PROJECT,
1914
SME_MAX_CONVERSATIONS_PER_PROJECT,
2015
} from "@okcode/contracts";
21-
import { DateTime, Effect, Fiber, Layer, Option, Random, Ref } from "effect";
16+
import { DateTime, Effect, Layer, Option, Random, Ref } from "effect";
2217
import crypto from "node:crypto";
2318

2419
import { SmeKnowledgeDocumentRepository } from "../../persistence/Services/SmeKnowledgeDocuments.ts";

0 commit comments

Comments
 (0)