Skip to content

Commit 4285d71

Browse files
committed
(feat) implement Conversation and Message classes with serialization and message management
1 parent df3bbfd commit 4285d71

3 files changed

Lines changed: 137 additions & 0 deletions

File tree

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { randomUUID, type UUID } from "node:crypto";
2+
import type { Message } from "@/message.js"
3+
4+
function dumpConversationToBytes(c: Conversation): Uint8Array {
5+
const payload = {
6+
uuid: c.uuid,
7+
messages: c.messages.map((message) => {
8+
const base = {
9+
uuid: message.uuid,
10+
timestamp: message.timestamp.toISOString(),
11+
role: message.role,
12+
encodedContent: Array.from(message.encodedContent.bytes),
13+
};
14+
15+
if (message.role === "assistant" && message.toolCalls) {
16+
return { ...base, toolCalls: message.toolCalls };
17+
}
18+
19+
if (message.role === "tool") {
20+
return { ...base, toolCallId: message.toolCallId };
21+
}
22+
23+
return base;
24+
}),
25+
};
26+
27+
return new TextEncoder().encode(JSON.stringify(payload));
28+
}
29+
30+
export type SearchMessageResult<Message, E = Error> =
31+
| { ok: true, value: Message }
32+
| { ok: false, error: E };
33+
34+
export class Conversation {
35+
readonly #uuid: UUID;
36+
#messages: Message[];
37+
38+
private constructor(messages: Message[]) {
39+
this.#uuid = randomUUID();
40+
this.#messages = messages;
41+
}
42+
43+
static fromMessages(messages?: Message[]) {
44+
const m = (messages && messages?.length != 0) ? messages : [] as Message[];
45+
return new Conversation(m);
46+
}
47+
48+
get uuid(): UUID {
49+
return this.#uuid;
50+
}
51+
52+
get messages(): Message[] {
53+
return this.#messages;
54+
}
55+
56+
searchMessage(uuid: UUID): SearchMessageResult<Message, "message_not_found"> {
57+
if (this.#messages.length <= 0) {
58+
return { ok: false, error: "message_not_found" };
59+
}
60+
61+
for (let i = 0; i < this.#messages.length; i++) {
62+
const message = this.#messages[i];
63+
if (message?.uuid === uuid) return { ok: true, value: message };
64+
}
65+
66+
return { ok: false, error: "message_not_found" };
67+
}
68+
69+
addMessage(message: Message): void {
70+
this.#messages = [...this.#messages, message] as Message[];
71+
}
72+
73+
dumpToBytes(): Uint8Array { return dumpConversationToBytes(this); }
74+
75+
}

packages/core-sdk/src/Message.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import type { UUID } from "node:crypto";
2+
3+
export class EncodedContent {
4+
readonly #bytes: Uint8Array;
5+
6+
private constructor(bytes: Uint8Array) {
7+
this.#bytes = bytes;
8+
}
9+
10+
static fromString(text: string): EncodedContent {
11+
return new EncodedContent(new TextEncoder().encode(text));
12+
}
13+
14+
get size(): number {
15+
return this.#bytes.length;
16+
}
17+
18+
get bytes(): Uint8Array {
19+
return this.#bytes;
20+
}
21+
22+
decode(): string {
23+
return new TextDecoder("utf-8").decode(this.#bytes);
24+
}
25+
}
26+
27+
type ToolCallId = string & { readonly __brand: "ToolCallId" };
28+
export const toolCallId = (s: string): ToolCallId => s as ToolCallId;
29+
30+
export type ToolCall = {
31+
readonly toolCallId: ToolCallId,
32+
readonly name: string,
33+
readonly arguments: { [key: string]: unknown }
34+
}
35+
36+
export interface MessageBase {
37+
readonly uuid: UUID;
38+
readonly timestamp: Date;
39+
readonly encodedContent: EncodedContent;
40+
}
41+
42+
export type Message =
43+
| (MessageBase & {readonly role: "user"})
44+
| (MessageBase & {readonly role: "assistant", readonly toolCalls?: ToolCall[]})
45+
| (MessageBase & {readonly role: "system"})
46+
| (MessageBase & {readonly role: "tool", readonly toolCallId: ToolCallId})

packages/core-sdk/src/Provider.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Agent as HttpsAgent } from "node:https";
2+
import { URL } from "node:url";
3+
4+
export interface Provider {
5+
readonly identifier: string;
6+
}
7+
8+
export type HttpsProviderConfig = {
9+
baseUrl: URL
10+
};
11+
12+
export interface HttpsProvider extends Provider {
13+
readonly config: HttpsProviderConfig;
14+
readonly baseUrl: URL;
15+
readonly httpsAgent: HttpsAgent;
16+
}

0 commit comments

Comments
 (0)