openAgent
gitlabThe open source UNIVERSAL agent.
clone
https://gitlab.com/bitzzdev/openAgent.gitAIagentautomationopen-sourceuniversal-agent
# Message ShapeProblem:- stored messages need enough data to replay and resume a session later- prompt hooks often just want to append a synthetic user/assistant message- today that means faking ids, timestamps, and request metadata## Option 1: Two Message ShapesKeep `User` / `Assistant` for stored history, but clean them up.```tstype User = {role: "user"time: { created: number }request: {agent: stringmodel: ModelRefvariant?: stringformat?: OutputFormatsystem?: stringtools?: Record<string, boolean>}}type Assistant = {role: "assistant"run: { agent: string; model: ModelRef; path: { cwd: string; root: string } }usage: { cost: number; tokens: Tokens }result: { finish?: string; error?: Error; structured?: unknown; kind: "reply" | "summary" }}```Add a separate transient `PromptMessage` for prompt surgery.```tstype PromptMessage = {role: "user" | "assistant"parts: PromptPart[]}```Plugin hook example:```tsprompt.push({role: "user",parts: [{ type: "text", text: "Summarize the tool output above and continue." }],})```Tradeoff: prompt hooks get easy lightweight messages, but there are now two message shapes.## Option 2: Prompt MutatorsKeep `User` / `Assistant` as the stored history model.Prompt hooks do not build messages directly. The runtime gives them prompt mutators.```tstype PromptEditor = {append(input: { role: "user" | "assistant"; parts: PromptPart[] }): voidprepend(input: { role: "user" | "assistant"; parts: PromptPart[] }): voidappendTo(target: "last-user" | "last-assistant", parts: PromptPart[]): voidinsertAfter(messageID: string, input: { role: "user" | "assistant"; parts: PromptPart[] }): voidinsertBefore(messageID: string, input: { role: "user" | "assistant"; parts: PromptPart[] }): void}```Plugin hook examples:```tsprompt.append({role: "user",parts: [{ type: "text", text: "Summarize the tool output above and continue." }],})``````tsprompt.appendTo("last-user", [{ type: "text", text: BUILD_SWITCH }])```Tradeoff: avoids a second full message type and avoids fake ids/timestamps, but moves more magic into the hook API.## Option 3: Separate Turn StateMove execution settings out of `User` and into a separate turn/request object.```tstype Turn = {id: stringrequest: {agent: stringmodel: ModelRefvariant?: stringformat?: OutputFormatsystem?: stringtools?: Record<string, boolean>}}type User = {role: "user"turnID: stringtime: { created: number }}type Assistant = {role: "assistant"turnID: stringusage: { cost: number; tokens: Tokens }result: { finish?: string; error?: Error; structured?: unknown; kind: "reply" | "summary" }}```Examples:```tsconst turn = {request: {agent: "build",model: { providerID: "openai", modelID: "gpt-5" },},}``````tsconst msg = {role: "user",turnID: turn.id,parts: [{ type: "text", text: "Summarize the tool output above and continue." }],}```Tradeoff: stored messages get much smaller and cleaner, but replay now has to join messages with turn state and prompt hooks still need a way to pick which turn they belong to.