@minpeter/pss-runtime 0.0.5 → 0.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -32,11 +32,53 @@ for await (const event of run.stream()) {
32
32
 
33
33
  `agent.send(...)` is shorthand for `agent.session("default").send(...)`.
34
34
 
35
+ For model providers that support multimodal input, send JSON-serializable content
36
+ parts through the same API. String input and `readonly string[]` remain supported
37
+ shortcuts for text-only turns.
38
+
39
+ ```ts
40
+ const run = await agent.send([
41
+ { type: "text", text: "Describe this UI screenshot." },
42
+ {
43
+ type: "image",
44
+ image: "data:image/png;base64,iVBORw0KGgo...",
45
+ mediaType: "image/png",
46
+ },
47
+ ]);
48
+ ```
49
+
50
+ File parts use the same JSON-serializable shape when the selected model supports
51
+ file input:
52
+
53
+ ```ts
54
+ await agent.send([
55
+ { type: "text", text: "Summarize the attached report." },
56
+ {
57
+ type: "file",
58
+ data: "data:application/pdf;base64,JVBERi0x...",
59
+ filename: "report.pdf",
60
+ mediaType: "application/pdf",
61
+ },
62
+ ]);
63
+ ```
64
+
65
+ The runtime normalizes and persists these content parts as session continuation
66
+ state; it does not fetch remote media, decode files, or guarantee provider support
67
+ for every media type.
68
+
69
+ The public transcript protocol is `AgentEvent`: live runs emit runtime-defined
70
+ events through `run.stream()`. Provider/model message history is internal
71
+ continuation state, not a public history API.
72
+
35
73
  ## Session storage and portability
36
74
 
37
75
  The runtime owns full session state encoding and history compaction semantics.
38
76
  Adapters own persistence only through `SessionStore`:
39
77
 
78
+ Stored session state is an opaque, versioned runtime snapshot for continuation.
79
+ Do not inspect it as a replay log; exact replay should be modeled separately as
80
+ an `AgentEvent` log if that capability is added later.
81
+
40
82
  ```ts
41
83
  import type { SessionStore } from "@minpeter/pss-runtime";
42
84
  import { MemorySessionStore } from "@minpeter/pss-runtime/session-store/memory";
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { AgentMessage, AgentModel, AgentTool, AgentToolExecute, AgentToolExecutionOptions, AgentTools, LlmOutputPart, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, createLlm } from "./llm.js";
2
- import { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, ToolCall, ToolResult, UserText, UserTextContent } from "./session/events.js";
1
+ import { AgentModel, AgentTool, AgentToolExecute, AgentToolExecutionOptions, AgentTools, LlmOutputPart, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, createLlm } from "./llm.js";
2
+ import { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, ToolCall, ToolResult, UserMessage, UserMessageContent, UserMessageContentPart, UserMessageFileData, UserMessageFilePart, UserMessageImagePart, UserMessageTextPart, UserText, UserTextContent } from "./session/events.js";
3
3
  import { AgentRun } from "./session/run.js";
4
4
  import { CommitResult, ExpectedSessionVersion, SessionStore, StoredSession } from "./session/store/types.js";
5
- import { AgentInput } from "./session/session.js";
5
+ import { AgentInput, SessionInput, UserInput } from "./session/session.js";
6
6
  import { Agent, AgentOptions, AgentSessionOptions, SessionHandle } from "./agent.js";
7
7
  import { AgentLoopResult, runAgentLoop } from "./agent-loop.js";
8
- export { Agent, type AgentEvent, type AgentEventListener, type AgentInput, type AgentLoopResult, type AgentMessage, type AgentModel, type AgentOptions, type AgentRun, type AgentSessionOptions, type AgentTool, type AgentToolExecute, type AgentToolExecutionOptions, type AgentTools, type AssistantReasoning, type AssistantText, type CommitResult, type ExpectedSessionVersion, type LlmOutputPart, type RuntimeCreateLlmOptions, type RuntimeLlm, type RuntimeLlmContext, type RuntimeLlmOutput, type SessionHandle, type SessionStore, type StoredSession, type ToolCall, type ToolResult, type UserText, type UserTextContent, createLlm, runAgentLoop };
8
+ export { Agent, type AgentEvent, type AgentEventListener, type AgentInput, type AgentLoopResult, type AgentModel, type AgentOptions, type AgentRun, type AgentSessionOptions, type AgentTool, type AgentToolExecute, type AgentToolExecutionOptions, type AgentTools, type AssistantReasoning, type AssistantText, type CommitResult, type ExpectedSessionVersion, type LlmOutputPart, type RuntimeCreateLlmOptions, type RuntimeLlm, type RuntimeLlmContext, type RuntimeLlmOutput, type SessionHandle, type SessionInput, type SessionStore, type StoredSession, type ToolCall, type ToolResult, type UserInput, type UserMessage, type UserMessageContent, type UserMessageContentPart, type UserMessageFileData, type UserMessageFilePart, type UserMessageImagePart, type UserMessageTextPart, type UserText, type UserTextContent, createLlm, runAgentLoop };
package/dist/llm.d.ts CHANGED
@@ -6,7 +6,6 @@ type AgentToolExecute = NonNullable<Tool["execute"]>;
6
6
  type AgentTool = Tool;
7
7
  type AgentTools = ToolSet;
8
8
  type AgentModel = LanguageModel;
9
- type AgentMessage = ModelMessage;
10
9
  type LlmOutput = Awaited<ReturnType<typeof generateText>>["responseMessages"];
11
10
  type LlmOutputPart = LlmOutput[number];
12
11
  interface LlmContext {
@@ -29,5 +28,5 @@ declare function createLlm({
29
28
  tools
30
29
  }: CreateLlmOptions): Llm;
31
30
  //#endregion
32
- export { AgentMessage, AgentModel, AgentTool, AgentToolExecute, AgentToolExecutionOptions, AgentTools, Llm, LlmOutputPart, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, createLlm };
31
+ export { AgentModel, AgentTool, AgentToolExecute, AgentToolExecutionOptions, AgentTools, Llm, LlmOutputPart, RuntimeCreateLlmOptions, RuntimeLlm, RuntimeLlmContext, RuntimeLlmOutput, createLlm };
33
32
  //# sourceMappingURL=llm.d.ts.map
@@ -4,6 +4,40 @@ interface UserText {
4
4
  text: UserTextContent;
5
5
  type: "user-text";
6
6
  }
7
+ interface UserMessageTextPart {
8
+ text: string;
9
+ type: "text";
10
+ }
11
+ interface UserMessageImagePart {
12
+ image: string;
13
+ mediaType?: string;
14
+ type: "image";
15
+ }
16
+ type UserMessageFileData = string | {
17
+ data: string;
18
+ type: "data";
19
+ } | {
20
+ reference: Record<string, string>;
21
+ type: "reference";
22
+ } | {
23
+ text: string;
24
+ type: "text";
25
+ } | {
26
+ type: "url";
27
+ url: string;
28
+ };
29
+ interface UserMessageFilePart {
30
+ data: UserMessageFileData;
31
+ filename?: string;
32
+ mediaType: string;
33
+ type: "file";
34
+ }
35
+ type UserMessageContentPart = UserMessageFilePart | UserMessageImagePart | UserMessageTextPart;
36
+ type UserMessageContent = readonly UserMessageContentPart[];
37
+ interface UserMessage {
38
+ content: UserMessageContent;
39
+ type: "user-message";
40
+ }
7
41
  interface AssistantText {
8
42
  text: string;
9
43
  type: "assistant-text";
@@ -24,7 +58,7 @@ interface ToolResult {
24
58
  toolName: string;
25
59
  type: "tool-result";
26
60
  }
27
- type AgentEvent = /** User input was accepted into the session queue. */UserText /** A queued user input started running as a turn. */ | {
61
+ type AgentEvent = /** User input was accepted into the session queue. */UserMessage | UserText /** User multipart input was accepted into the session queue. */ | UserMessage /** A queued user input started running as a turn. */ | {
28
62
  type: "turn-start";
29
63
  } /** The active turn was interrupted before normal completion. */ | {
30
64
  type: "turn-abort";
@@ -40,5 +74,5 @@ type AgentEvent = /** User input was accepted into the session queue. */UserText
40
74
  };
41
75
  type AgentEventListener = (event: AgentEvent) => void;
42
76
  //#endregion
43
- export { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, ToolCall, ToolResult, UserText, UserTextContent };
77
+ export { AgentEvent, AgentEventListener, AssistantReasoning, AssistantText, ToolCall, ToolResult, UserMessage, UserMessageContent, UserMessageContentPart, UserMessageFileData, UserMessageFilePart, UserMessageImagePart, UserMessageTextPart, UserText, UserTextContent };
44
78
  //# sourceMappingURL=events.d.ts.map
@@ -1,4 +1,4 @@
1
- import { userTextToModelMessage } from "./mapping.js";
1
+ import { userInputToModelMessage } from "./mapping.js";
2
2
  //#region src/session/history.ts
3
3
  var AgentModelHistory = class {
4
4
  #modelHistory = [];
@@ -11,7 +11,7 @@ var AgentModelHistory = class {
11
11
  return structuredClone(this.#modelHistory);
12
12
  }
13
13
  appendUserInput(input) {
14
- this.#modelHistory.push(userTextToModelMessage(input));
14
+ this.#modelHistory.push(userInputToModelMessage(input));
15
15
  this.#triggerChange();
16
16
  }
17
17
  appendModelMessage(message) {
@@ -1 +1 @@
1
- {"version":3,"file":"history.js","names":["#modelHistory","#onChange","#triggerChange"],"sources":["../../src/session/history.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { UserText } from \"./events\";\nimport { userTextToModelMessage } from \"./mapping\";\n\nexport class AgentModelHistory {\n readonly #modelHistory: ModelMessage[] = [];\n readonly #onChange?: (snapshot: ModelMessage[]) => void;\n\n constructor(\n history?: ModelMessage[],\n onChange?: (snapshot: ModelMessage[]) => void\n ) {\n if (history) {\n this.#modelHistory = structuredClone(history);\n }\n this.#onChange = onChange;\n }\n\n modelSnapshot(): ModelMessage[] {\n return structuredClone(this.#modelHistory);\n }\n\n appendUserInput(input: UserText): void {\n this.#modelHistory.push(userTextToModelMessage(input));\n this.#triggerChange();\n }\n\n appendModelMessage(message: ModelMessage): void {\n this.#modelHistory.push(structuredClone(message));\n this.#triggerChange();\n }\n\n rollback(snapshot: ModelMessage[]): void {\n this.#modelHistory.length = 0;\n this.#modelHistory.push(...structuredClone(snapshot));\n this.#triggerChange();\n }\n\n #triggerChange(): void {\n this.#onChange?.(this.modelSnapshot());\n }\n}\n"],"mappings":";;AAIA,IAAa,oBAAb,MAA+B;CAC7B,gBAAyC,CAAC;CAC1C;CAEA,YACE,SACA,UACA;EACA,IAAI,SACF,KAAKA,gBAAgB,gBAAgB,OAAO;EAE9C,KAAKC,YAAY;CACnB;CAEA,gBAAgC;EAC9B,OAAO,gBAAgB,KAAKD,aAAa;CAC3C;CAEA,gBAAgB,OAAuB;EACrC,KAAKA,cAAc,KAAK,uBAAuB,KAAK,CAAC;EACrD,KAAKE,eAAe;CACtB;CAEA,mBAAmB,SAA6B;EAC9C,KAAKF,cAAc,KAAK,gBAAgB,OAAO,CAAC;EAChD,KAAKE,eAAe;CACtB;CAEA,SAAS,UAAgC;EACvC,KAAKF,cAAc,SAAS;EAC5B,KAAKA,cAAc,KAAK,GAAG,gBAAgB,QAAQ,CAAC;EACpD,KAAKE,eAAe;CACtB;CAEA,iBAAuB;EACrB,KAAKD,YAAY,KAAK,cAAc,CAAC;CACvC;AACF"}
1
+ {"version":3,"file":"history.js","names":["#modelHistory","#onChange","#triggerChange"],"sources":["../../src/session/history.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport { userInputToModelMessage } from \"./mapping\";\nimport type { UserInput } from \"./session\";\n\nexport class AgentModelHistory {\n readonly #modelHistory: ModelMessage[] = [];\n readonly #onChange?: (snapshot: ModelMessage[]) => void;\n\n constructor(\n history?: ModelMessage[],\n onChange?: (snapshot: ModelMessage[]) => void\n ) {\n if (history) {\n this.#modelHistory = structuredClone(history);\n }\n this.#onChange = onChange;\n }\n\n modelSnapshot(): ModelMessage[] {\n return structuredClone(this.#modelHistory);\n }\n\n appendUserInput(input: UserInput): void {\n this.#modelHistory.push(userInputToModelMessage(input));\n this.#triggerChange();\n }\n\n appendModelMessage(message: ModelMessage): void {\n this.#modelHistory.push(structuredClone(message));\n this.#triggerChange();\n }\n\n rollback(snapshot: ModelMessage[]): void {\n this.#modelHistory.length = 0;\n this.#modelHistory.push(...structuredClone(snapshot));\n this.#triggerChange();\n }\n\n #triggerChange(): void {\n this.#onChange?.(this.modelSnapshot());\n }\n}\n"],"mappings":";;AAIA,IAAa,oBAAb,MAA+B;CAC7B,gBAAyC,CAAC;CAC1C;CAEA,YACE,SACA,UACA;EACA,IAAI,SACF,KAAKA,gBAAgB,gBAAgB,OAAO;EAE9C,KAAKC,YAAY;CACnB;CAEA,gBAAgC;EAC9B,OAAO,gBAAgB,KAAKD,aAAa;CAC3C;CAEA,gBAAgB,OAAwB;EACtC,KAAKA,cAAc,KAAK,wBAAwB,KAAK,CAAC;EACtD,KAAKE,eAAe;CACtB;CAEA,mBAAmB,SAA6B;EAC9C,KAAKF,cAAc,KAAK,gBAAgB,OAAO,CAAC;EAChD,KAAKE,eAAe;CACtB;CAEA,SAAS,UAAgC;EACvC,KAAKF,cAAc,SAAS;EAC5B,KAAKA,cAAc,KAAK,GAAG,gBAAgB,QAAQ,CAAC;EACpD,KAAKE,eAAe;CACtB;CAEA,iBAAuB;EACrB,KAAKD,YAAY,KAAK,cAAc,CAAC;CACvC;AACF"}
@@ -1,4 +1,8 @@
1
1
  //#region src/session/mapping.ts
2
+ function userInputToModelMessage(input) {
3
+ if (input.type === "user-message") return userMessageToModelMessage(input);
4
+ return userTextToModelMessage(input);
5
+ }
2
6
  function userTextToModelMessage(input) {
3
7
  return {
4
8
  role: "user",
@@ -12,6 +16,48 @@ function userTextContentToUserContent(text) {
12
16
  text: part
13
17
  }));
14
18
  }
19
+ function userMessageToModelMessage(input) {
20
+ return {
21
+ role: "user",
22
+ content: userMessageContentToUserContent(input.content)
23
+ };
24
+ }
25
+ function userMessageContentToUserContent(content) {
26
+ return content.map(userMessageContentPartToUserContentPart);
27
+ }
28
+ function userMessageContentPartToUserContentPart(part) {
29
+ if (part.type === "text") return {
30
+ type: "text",
31
+ text: part.text
32
+ };
33
+ if (part.type === "image") return {
34
+ type: "file",
35
+ data: part.image,
36
+ mediaType: part.mediaType ?? "image"
37
+ };
38
+ return {
39
+ type: "file",
40
+ data: userMessageFileDataToFileData(part.data),
41
+ mediaType: part.mediaType,
42
+ ...part.filename === void 0 ? {} : { filename: part.filename }
43
+ };
44
+ }
45
+ function userMessageFileDataToFileData(data) {
46
+ if (typeof data === "string") return data;
47
+ if (data.type === "url") return data.url;
48
+ if (data.type === "data") return {
49
+ type: "data",
50
+ data: data.data
51
+ };
52
+ if (data.type === "reference") return {
53
+ type: "reference",
54
+ reference: { ...data.reference }
55
+ };
56
+ return {
57
+ type: "text",
58
+ text: data.text
59
+ };
60
+ }
15
61
  function modelMessageToAgentEvents(message) {
16
62
  if (message.role === "assistant") return assistantReasoningFirstParts(assistantContentParts(message)).flatMap(assistantContentPartToEvents);
17
63
  if (message.role === "tool") return message.content.flatMap(toolContentPartToEvents);
@@ -56,6 +102,6 @@ function toolResultPartToEvents(part) {
56
102
  }];
57
103
  }
58
104
  //#endregion
59
- export { modelMessageToAgentEvents, userTextToModelMessage };
105
+ export { modelMessageToAgentEvents, userInputToModelMessage };
60
106
 
61
107
  //# sourceMappingURL=mapping.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mapping.js","names":[],"sources":["../../src/session/mapping.ts"],"sourcesContent":["import type {\n AssistantContent,\n AssistantModelMessage,\n ModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from \"ai\";\nimport type {\n AssistantReasoning,\n AssistantText,\n ToolCall,\n ToolResult,\n UserText,\n UserTextContent,\n} from \"./events\";\n\ntype AssistantContentPart = Exclude<AssistantContent, string>[number];\ntype ToolContentPart = ToolModelMessage[\"content\"][number];\ntype ModelEvent = AssistantReasoning | AssistantText | ToolCall | ToolResult;\n\n// UserText -> AI SDK UserModelMessage\nexport function userTextToModelMessage(input: UserText): UserModelMessage {\n return { role: \"user\", content: userTextContentToUserContent(input.text) };\n}\n\nfunction userTextContentToUserContent(\n text: UserTextContent\n): UserModelMessage[\"content\"] {\n if (typeof text === \"string\") {\n return text;\n }\n\n return text.map((part) => ({ type: \"text\", text: part }));\n}\n\n// AI SDK ModelMessage -> public agent events\nexport function modelMessageToAgentEvents(message: ModelMessage): ModelEvent[] {\n if (message.role === \"assistant\") {\n return assistantReasoningFirstParts(assistantContentParts(message)).flatMap(\n assistantContentPartToEvents\n );\n }\n\n if (message.role === \"tool\") {\n return message.content.flatMap(toolContentPartToEvents);\n }\n\n return [];\n}\n\nfunction assistantContentParts(\n message: AssistantModelMessage\n): AssistantContentPart[] {\n return typeof message.content === \"string\"\n ? [{ type: \"text\", text: message.content }]\n : message.content;\n}\n\nfunction assistantReasoningFirstParts(\n parts: AssistantContentPart[]\n): AssistantContentPart[] {\n return [\n ...parts.filter((part) => part.type === \"reasoning\"),\n ...parts.filter((part) => part.type !== \"reasoning\"),\n ];\n}\n\nfunction assistantContentPartToEvents(\n part: AssistantContentPart\n): ModelEvent[] {\n if (part.type === \"text\") {\n return part.text ? [{ type: \"assistant-text\", text: part.text }] : [];\n }\n\n if (part.type === \"reasoning\") {\n return part.text ? [{ type: \"assistant-reasoning\", text: part.text }] : [];\n }\n\n if (part.type === \"tool-call\") {\n return [\n {\n type: \"tool-call\",\n input: part.input,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n }\n\n return [];\n}\n\nfunction toolContentPartToEvents(part: ToolContentPart): ModelEvent[] {\n if (part.type === \"tool-result\") {\n return toolResultPartToEvents(part);\n }\n\n return [];\n}\n\nfunction toolResultPartToEvents(part: {\n output: unknown;\n toolCallId: string;\n toolName: string;\n type: \"tool-result\";\n}): ModelEvent[] {\n return [\n {\n type: \"tool-result\",\n output: part.output,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n}\n"],"mappings":";AAqBA,SAAgB,uBAAuB,OAAmC;CACxE,OAAO;EAAE,MAAM;EAAQ,SAAS,6BAA6B,MAAM,IAAI;CAAE;AAC3E;AAEA,SAAS,6BACP,MAC6B;CAC7B,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,OAAO,KAAK,KAAK,UAAU;EAAE,MAAM;EAAQ,MAAM;CAAK,EAAE;AAC1D;AAGA,SAAgB,0BAA0B,SAAqC;CAC7E,IAAI,QAAQ,SAAS,aACnB,OAAO,6BAA6B,sBAAsB,OAAO,CAAC,EAAE,QAClE,4BACF;CAGF,IAAI,QAAQ,SAAS,QACnB,OAAO,QAAQ,QAAQ,QAAQ,uBAAuB;CAGxD,OAAO,CAAC;AACV;AAEA,SAAS,sBACP,SACwB;CACxB,OAAO,OAAO,QAAQ,YAAY,WAC9B,CAAC;EAAE,MAAM;EAAQ,MAAM,QAAQ;CAAQ,CAAC,IACxC,QAAQ;AACd;AAEA,SAAS,6BACP,OACwB;CACxB,OAAO,CACL,GAAG,MAAM,QAAQ,SAAS,KAAK,SAAS,WAAW,GACnD,GAAG,MAAM,QAAQ,SAAS,KAAK,SAAS,WAAW,CACrD;AACF;AAEA,SAAS,6BACP,MACc;CACd,IAAI,KAAK,SAAS,QAChB,OAAO,KAAK,OAAO,CAAC;EAAE,MAAM;EAAkB,MAAM,KAAK;CAAK,CAAC,IAAI,CAAC;CAGtE,IAAI,KAAK,SAAS,aAChB,OAAO,KAAK,OAAO,CAAC;EAAE,MAAM;EAAuB,MAAM,KAAK;CAAK,CAAC,IAAI,CAAC;CAG3E,IAAI,KAAK,SAAS,aAChB,OAAO,CACL;EACE,MAAM;EACN,OAAO,KAAK;EACZ,YAAY,KAAK;EACjB,UAAU,KAAK;CACjB,CACF;CAGF,OAAO,CAAC;AACV;AAEA,SAAS,wBAAwB,MAAqC;CACpE,IAAI,KAAK,SAAS,eAChB,OAAO,uBAAuB,IAAI;CAGpC,OAAO,CAAC;AACV;AAEA,SAAS,uBAAuB,MAKf;CACf,OAAO,CACL;EACE,MAAM;EACN,QAAQ,KAAK;EACb,YAAY,KAAK;EACjB,UAAU,KAAK;CACjB,CACF;AACF"}
1
+ {"version":3,"file":"mapping.js","names":[],"sources":["../../src/session/mapping.ts"],"sourcesContent":["import type {\n AssistantContent,\n AssistantModelMessage,\n ModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from \"ai\";\nimport type {\n AssistantReasoning,\n AssistantText,\n ToolCall,\n ToolResult,\n UserMessage,\n UserMessageContent,\n UserMessageContentPart,\n UserMessageFileData,\n UserText,\n UserTextContent,\n} from \"./events\";\nimport type { UserInput } from \"./session\";\n\ntype AssistantContentPart = Exclude<AssistantContent, string>[number];\ntype ToolContentPart = ToolModelMessage[\"content\"][number];\ntype ModelEvent = AssistantReasoning | AssistantText | ToolCall | ToolResult;\n\n// UserInput -> AI SDK UserModelMessage\nexport function userInputToModelMessage(input: UserInput): UserModelMessage {\n if (input.type === \"user-message\") {\n return userMessageToModelMessage(input);\n }\n\n return userTextToModelMessage(input);\n}\n\nexport function userTextToModelMessage(input: UserText): UserModelMessage {\n return { role: \"user\", content: userTextContentToUserContent(input.text) };\n}\n\nfunction userTextContentToUserContent(\n text: UserTextContent\n): UserModelMessage[\"content\"] {\n if (typeof text === \"string\") {\n return text;\n }\n\n return text.map((part) => ({ type: \"text\", text: part }));\n}\n\nexport function userMessageToModelMessage(\n input: UserMessage\n): UserModelMessage {\n return {\n role: \"user\",\n content: userMessageContentToUserContent(input.content),\n };\n}\n\nfunction userMessageContentToUserContent(\n content: UserMessageContent\n): Exclude<UserModelMessage[\"content\"], string> {\n return content.map(userMessageContentPartToUserContentPart);\n}\n\nfunction userMessageContentPartToUserContentPart(\n part: UserMessageContentPart\n): Exclude<UserModelMessage[\"content\"], string>[number] {\n if (part.type === \"text\") {\n return { type: \"text\", text: part.text };\n }\n\n if (part.type === \"image\") {\n return {\n type: \"file\",\n data: part.image,\n mediaType: part.mediaType ?? \"image\",\n };\n }\n\n return {\n type: \"file\",\n data: userMessageFileDataToFileData(part.data),\n mediaType: part.mediaType,\n ...(part.filename === undefined ? {} : { filename: part.filename }),\n };\n}\n\nfunction userMessageFileDataToFileData(\n data: UserMessageFileData\n): Extract<\n Exclude<UserModelMessage[\"content\"], string>[number],\n { type: \"file\" }\n>[\"data\"] {\n if (typeof data === \"string\") {\n return data;\n }\n\n if (data.type === \"url\") {\n return data.url;\n }\n\n if (data.type === \"data\") {\n return { type: \"data\", data: data.data };\n }\n\n if (data.type === \"reference\") {\n return { type: \"reference\", reference: { ...data.reference } };\n }\n\n return { type: \"text\", text: data.text };\n}\n\n// AI SDK ModelMessage -> public agent events\nexport function modelMessageToAgentEvents(message: ModelMessage): ModelEvent[] {\n if (message.role === \"assistant\") {\n return assistantReasoningFirstParts(assistantContentParts(message)).flatMap(\n assistantContentPartToEvents\n );\n }\n\n if (message.role === \"tool\") {\n return message.content.flatMap(toolContentPartToEvents);\n }\n\n return [];\n}\n\nfunction assistantContentParts(\n message: AssistantModelMessage\n): AssistantContentPart[] {\n return typeof message.content === \"string\"\n ? [{ type: \"text\", text: message.content }]\n : message.content;\n}\n\nfunction assistantReasoningFirstParts(\n parts: AssistantContentPart[]\n): AssistantContentPart[] {\n return [\n ...parts.filter((part) => part.type === \"reasoning\"),\n ...parts.filter((part) => part.type !== \"reasoning\"),\n ];\n}\n\nfunction assistantContentPartToEvents(\n part: AssistantContentPart\n): ModelEvent[] {\n if (part.type === \"text\") {\n return part.text ? [{ type: \"assistant-text\", text: part.text }] : [];\n }\n\n if (part.type === \"reasoning\") {\n return part.text ? [{ type: \"assistant-reasoning\", text: part.text }] : [];\n }\n\n if (part.type === \"tool-call\") {\n return [\n {\n type: \"tool-call\",\n input: part.input,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n }\n\n return [];\n}\n\nfunction toolContentPartToEvents(part: ToolContentPart): ModelEvent[] {\n if (part.type === \"tool-result\") {\n return toolResultPartToEvents(part);\n }\n\n return [];\n}\n\nfunction toolResultPartToEvents(part: {\n output: unknown;\n toolCallId: string;\n toolName: string;\n type: \"tool-result\";\n}): ModelEvent[] {\n return [\n {\n type: \"tool-result\",\n output: part.output,\n toolCallId: part.toolCallId,\n toolName: part.toolName,\n },\n ];\n}\n"],"mappings":";AA0BA,SAAgB,wBAAwB,OAAoC;CAC1E,IAAI,MAAM,SAAS,gBACjB,OAAO,0BAA0B,KAAK;CAGxC,OAAO,uBAAuB,KAAK;AACrC;AAEA,SAAgB,uBAAuB,OAAmC;CACxE,OAAO;EAAE,MAAM;EAAQ,SAAS,6BAA6B,MAAM,IAAI;CAAE;AAC3E;AAEA,SAAS,6BACP,MAC6B;CAC7B,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,OAAO,KAAK,KAAK,UAAU;EAAE,MAAM;EAAQ,MAAM;CAAK,EAAE;AAC1D;AAEA,SAAgB,0BACd,OACkB;CAClB,OAAO;EACL,MAAM;EACN,SAAS,gCAAgC,MAAM,OAAO;CACxD;AACF;AAEA,SAAS,gCACP,SAC8C;CAC9C,OAAO,QAAQ,IAAI,uCAAuC;AAC5D;AAEA,SAAS,wCACP,MACsD;CACtD,IAAI,KAAK,SAAS,QAChB,OAAO;EAAE,MAAM;EAAQ,MAAM,KAAK;CAAK;CAGzC,IAAI,KAAK,SAAS,SAChB,OAAO;EACL,MAAM;EACN,MAAM,KAAK;EACX,WAAW,KAAK,aAAa;CAC/B;CAGF,OAAO;EACL,MAAM;EACN,MAAM,8BAA8B,KAAK,IAAI;EAC7C,WAAW,KAAK;EAChB,GAAI,KAAK,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,UAAU,KAAK,SAAS;CACnE;AACF;AAEA,SAAS,8BACP,MAIQ;CACR,IAAI,OAAO,SAAS,UAClB,OAAO;CAGT,IAAI,KAAK,SAAS,OAChB,OAAO,KAAK;CAGd,IAAI,KAAK,SAAS,QAChB,OAAO;EAAE,MAAM;EAAQ,MAAM,KAAK;CAAK;CAGzC,IAAI,KAAK,SAAS,aAChB,OAAO;EAAE,MAAM;EAAa,WAAW,EAAE,GAAG,KAAK,UAAU;CAAE;CAG/D,OAAO;EAAE,MAAM;EAAQ,MAAM,KAAK;CAAK;AACzC;AAGA,SAAgB,0BAA0B,SAAqC;CAC7E,IAAI,QAAQ,SAAS,aACnB,OAAO,6BAA6B,sBAAsB,OAAO,CAAC,EAAE,QAClE,4BACF;CAGF,IAAI,QAAQ,SAAS,QACnB,OAAO,QAAQ,QAAQ,QAAQ,uBAAuB;CAGxD,OAAO,CAAC;AACV;AAEA,SAAS,sBACP,SACwB;CACxB,OAAO,OAAO,QAAQ,YAAY,WAC9B,CAAC;EAAE,MAAM;EAAQ,MAAM,QAAQ;CAAQ,CAAC,IACxC,QAAQ;AACd;AAEA,SAAS,6BACP,OACwB;CACxB,OAAO,CACL,GAAG,MAAM,QAAQ,SAAS,KAAK,SAAS,WAAW,GACnD,GAAG,MAAM,QAAQ,SAAS,KAAK,SAAS,WAAW,CACrD;AACF;AAEA,SAAS,6BACP,MACc;CACd,IAAI,KAAK,SAAS,QAChB,OAAO,KAAK,OAAO,CAAC;EAAE,MAAM;EAAkB,MAAM,KAAK;CAAK,CAAC,IAAI,CAAC;CAGtE,IAAI,KAAK,SAAS,aAChB,OAAO,KAAK,OAAO,CAAC;EAAE,MAAM;EAAuB,MAAM,KAAK;CAAK,CAAC,IAAI,CAAC;CAG3E,IAAI,KAAK,SAAS,aAChB,OAAO,CACL;EACE,MAAM;EACN,OAAO,KAAK;EACZ,YAAY,KAAK;EACjB,UAAU,KAAK;CACjB,CACF;CAGF,OAAO,CAAC;AACV;AAEA,SAAS,wBAAwB,MAAqC;CACpE,IAAI,KAAK,SAAS,eAChB,OAAO,uBAAuB,IAAI;CAGpC,OAAO,CAAC;AACV;AAEA,SAAS,uBAAuB,MAKf;CACf,OAAO,CACL;EACE,MAAM;EACN,QAAQ,KAAK;EACb,YAAY,KAAK;EACjB,UAAU,KAAK;CACjB,CACF;AACF"}
@@ -1,8 +1,10 @@
1
- import { UserText } from "./events.js";
1
+ import { UserMessage, UserMessageContentPart, UserText } from "./events.js";
2
2
  import { AgentRun } from "./run.js";
3
3
 
4
4
  //#region src/session/session.d.ts
5
- type AgentInput = string | readonly string[] | UserText;
5
+ type UserInput = UserMessage | UserText;
6
+ type AgentInput = readonly string[] | readonly UserMessageContentPart[] | string | UserInput;
7
+ type SessionInput = AgentInput;
6
8
  //#endregion
7
- export { AgentInput };
9
+ export { AgentInput, SessionInput, UserInput };
8
10
  //# sourceMappingURL=session.d.ts.map
@@ -1,6 +1,7 @@
1
1
  import { runAgentLoop } from "../agent-loop.js";
2
2
  import { AgentModelHistory } from "./history.js";
3
3
  import { BufferedAgentRun } from "./run.js";
4
+ import { decodeStoredSessionSnapshot, encodeSessionSnapshot } from "./snapshot.js";
4
5
  //#region src/session/session.ts
5
6
  var AgentSession = class {
6
7
  #inputQueue = [];
@@ -71,7 +72,7 @@ var AgentSession = class {
71
72
  async #replaceWithStoredSession() {
72
73
  const stored = await this.#persistence.store.load(this.#persistence.key);
73
74
  this.#storeVersion = stored?.version;
74
- this.#history = new AgentModelHistory(decodeStoredHistory(stored));
75
+ this.#history = new AgentModelHistory(decodeStoredSessionSnapshot(stored));
75
76
  }
76
77
  async #drainInputQueue() {
77
78
  if (this.#running) return;
@@ -129,7 +130,7 @@ var AgentSession = class {
129
130
  }
130
131
  async #commitHistory() {
131
132
  const result = await this.#persistence.store.commit(this.#persistence.key, {
132
- state: encodeHistory(this.#history.modelSnapshot()),
133
+ state: encodeSessionSnapshot(this.#history.modelSnapshot()),
133
134
  version: this.#storeVersion
134
135
  }, { expectedVersion: this.#storeVersion ?? null });
135
136
  if (!result.ok) {
@@ -148,22 +149,43 @@ function normalizeAgentInput(input) {
148
149
  type: "user-text",
149
150
  text: structuredClone(input)
150
151
  };
152
+ if (isArrayInput(input)) {
153
+ assertUserMessageContent(input);
154
+ return {
155
+ type: "user-message",
156
+ content: structuredClone(input)
157
+ };
158
+ }
159
+ if (isUserMessage(input)) assertUserMessageContent(input.content);
151
160
  return structuredClone(input);
152
161
  }
153
162
  function isStringArrayInput(input) {
163
+ return isArrayInput(input) && input.every((part) => typeof part === "string");
164
+ }
165
+ function isArrayInput(input) {
154
166
  return Array.isArray(input);
155
167
  }
156
- function encodeHistory(history) {
157
- return {
158
- schemaVersion: 1,
159
- history
160
- };
168
+ function isUserMessage(input) {
169
+ return input.type === "user-message";
170
+ }
171
+ function assertUserMessageContent(input) {
172
+ for (const part of input) if (!isUserMessageContentPart(part)) throw new TypeError("Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.");
173
+ }
174
+ function isUserMessageContentPart(part) {
175
+ if (part === null || typeof part !== "object" || !("type" in part)) return false;
176
+ if (part.type === "text") return "text" in part && typeof part.text === "string";
177
+ if (part.type === "image") return "image" in part && typeof part.image === "string" && (!("mediaType" in part) || typeof part.mediaType === "string");
178
+ if (part.type === "file") return "data" in part && isUserMessageFileData(part.data) && "mediaType" in part && typeof part.mediaType === "string" && (!("filename" in part) || typeof part.filename === "string");
179
+ return false;
161
180
  }
162
- function decodeStoredHistory(stored) {
163
- if (!stored) return [];
164
- const state = stored.state;
165
- if (state !== null && typeof state === "object" && "schemaVersion" in state && state.schemaVersion === 1 && "history" in state && Array.isArray(state.history)) return structuredClone(state.history);
166
- throw new Error("Unsupported stored session state");
181
+ function isUserMessageFileData(data) {
182
+ if (typeof data === "string") return true;
183
+ if (data === null || typeof data !== "object" || !("type" in data)) return false;
184
+ if (data.type === "data") return "data" in data && typeof data.data === "string";
185
+ if (data.type === "reference") return "reference" in data && data.reference !== null && typeof data.reference === "object" && Object.values(data.reference).every((value) => typeof value === "string");
186
+ if (data.type === "text") return "text" in data && typeof data.text === "string";
187
+ if (data.type === "url") return "url" in data && typeof data.url === "string";
188
+ return false;
167
189
  }
168
190
  function errorMessage(error) {
169
191
  if (error instanceof Error) return error.message;
@@ -1 +1 @@
1
- {"version":3,"file":"session.js","names":["#inputQueue","#llm","#persistence","#killed","#ensureLoaded","#drainInputQueue","#activeAbort","#loaded","#loadPromise","#loadSessionState","#replaceWithStoredSession","#storeVersion","#history","#running","#processQueuedInput","#commitHistory"],"sources":["../../src/session/session.ts"],"sourcesContent":["import { runAgentLoop } from \"../agent-loop\";\nimport type { AgentMessage, Llm } from \"../llm\";\nimport type { UserText } from \"./events\";\nimport { AgentModelHistory } from \"./history\";\nimport type { AgentRun } from \"./run\";\nimport { BufferedAgentRun } from \"./run\";\nimport type { SessionStore, StoredSession } from \"./store/types\";\n\nexport type AgentInput = string | readonly string[] | UserText;\nexport type SessionInput = AgentInput;\nexport type { AgentRun } from \"./run\";\n\ninterface SessionPersistenceOptions {\n readonly key: string;\n readonly store: SessionStore;\n}\n\ninterface QueuedInput {\n readonly input: UserText;\n readonly run: BufferedAgentRun;\n}\n\ninterface EncodedSessionState {\n readonly history: AgentMessage[];\n readonly schemaVersion: 1;\n}\n\nexport class AgentSession {\n readonly #inputQueue: QueuedInput[] = [];\n readonly #llm: Llm;\n readonly #persistence: SessionPersistenceOptions;\n #activeAbort?: AbortController;\n #history = new AgentModelHistory();\n #killed = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #running = false;\n #storeVersion: string | undefined;\n\n constructor(llm: Llm, persistence: SessionPersistenceOptions) {\n this.#llm = llm;\n this.#persistence = persistence;\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n run.emit(acceptedInput);\n this.#inputQueue.push({ input: structuredClone(acceptedInput), run });\n this.#drainInputQueue().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n this.#activeAbort?.abort();\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n item?.run.emit({\n type: \"turn-error\",\n message: sessionKilledError().message,\n });\n item?.run.close();\n }\n }\n\n async #ensureLoaded(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n this.#loadPromise ??= this.#loadSessionState();\n try {\n await this.#loadPromise;\n } catch (error) {\n this.#loadPromise = undefined;\n throw error;\n }\n }\n\n async #loadSessionState(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n await this.#replaceWithStoredSession();\n this.#loaded = true;\n }\n\n async #replaceWithStoredSession(): Promise<void> {\n const stored = await this.#persistence.store.load(this.#persistence.key);\n this.#storeVersion = stored?.version;\n this.#history = new AgentModelHistory(decodeStoredHistory(stored));\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await this.#processQueuedInput(item);\n }\n }\n } finally {\n this.#running = false;\n }\n }\n\n async #processQueuedInput({ input, run }: QueuedInput): Promise<void> {\n this.#activeAbort = new AbortController();\n const historySnapshot = this.#history.modelSnapshot();\n\n try {\n run.emit({ type: \"turn-start\" });\n this.#history.appendUserInput(input);\n await this.#commitHistory();\n\n const result = await runAgentLoop({\n emit: (event) => run.emit(event),\n history: this.#history,\n llm: this.#llm,\n signal: this.#activeAbort.signal,\n });\n\n await this.#commitHistory();\n run.emit({ type: result === \"aborted\" ? \"turn-abort\" : \"turn-end\" });\n } catch (error) {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n return;\n }\n\n this.#history.rollback(historySnapshot);\n try {\n await this.#commitHistory();\n } catch (rollbackError) {\n run.emit({\n type: \"turn-error\",\n message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(\n rollbackError\n )}`,\n });\n return;\n }\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n } finally {\n run.close();\n this.#activeAbort = undefined;\n }\n }\n\n async #commitHistory(): Promise<void> {\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n {\n state: encodeHistory(this.#history.modelSnapshot()),\n version: this.#storeVersion,\n },\n { expectedVersion: this.#storeVersion ?? null }\n );\n\n if (!result.ok) {\n await this.#replaceWithStoredSession();\n throw new SessionCommitConflictError(this.#persistence.key);\n }\n\n this.#storeVersion = result.version;\n }\n}\n\nexport function normalizeAgentInput(input: AgentInput): UserText {\n if (typeof input === \"string\") {\n return {\n type: \"user-text\",\n text: input,\n };\n }\n\n if (isStringArrayInput(input)) {\n return {\n type: \"user-text\",\n text: structuredClone(input) as readonly string[],\n };\n }\n\n return structuredClone(input);\n}\n\nfunction isStringArrayInput(input: AgentInput): input is readonly string[] {\n return Array.isArray(input);\n}\n\nfunction encodeHistory(history: AgentMessage[]): EncodedSessionState {\n return { schemaVersion: 1, history };\n}\n\nfunction decodeStoredHistory(stored: StoredSession | null): AgentMessage[] {\n if (!stored) {\n return [];\n }\n\n const state = stored.state;\n if (\n state !== null &&\n typeof state === \"object\" &&\n \"schemaVersion\" in state &&\n state.schemaVersion === 1 &&\n \"history\" in state &&\n Array.isArray(state.history)\n ) {\n return structuredClone(state.history) as AgentMessage[];\n }\n\n throw new Error(\"Unsupported stored session state\");\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nfunction sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nclass SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"session.js","names":["#inputQueue","#llm","#persistence","#killed","#ensureLoaded","#drainInputQueue","#activeAbort","#loaded","#loadPromise","#loadSessionState","#replaceWithStoredSession","#storeVersion","#history","#running","#processQueuedInput","#commitHistory"],"sources":["../../src/session/session.ts"],"sourcesContent":["import { runAgentLoop } from \"../agent-loop\";\nimport type { Llm } from \"../llm\";\nimport type { UserMessage, UserMessageContentPart, UserText } from \"./events\";\nimport { AgentModelHistory } from \"./history\";\nimport type { AgentRun } from \"./run\";\nimport { BufferedAgentRun } from \"./run\";\nimport { decodeStoredSessionSnapshot, encodeSessionSnapshot } from \"./snapshot\";\nimport type { SessionStore } from \"./store/types\";\n\nexport type UserInput = UserMessage | UserText;\nexport type AgentInput =\n | readonly string[]\n | readonly UserMessageContentPart[]\n | string\n | UserInput;\nexport type SessionInput = AgentInput;\nexport type { AgentRun } from \"./run\";\n\ninterface SessionPersistenceOptions {\n readonly key: string;\n readonly store: SessionStore;\n}\n\ninterface QueuedInput {\n readonly input: UserInput;\n readonly run: BufferedAgentRun;\n}\n\nexport class AgentSession {\n readonly #inputQueue: QueuedInput[] = [];\n readonly #llm: Llm;\n readonly #persistence: SessionPersistenceOptions;\n #activeAbort?: AbortController;\n #history = new AgentModelHistory();\n #killed = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #running = false;\n #storeVersion: string | undefined;\n\n constructor(llm: Llm, persistence: SessionPersistenceOptions) {\n this.#llm = llm;\n this.#persistence = persistence;\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n run.emit(acceptedInput);\n this.#inputQueue.push({ input: structuredClone(acceptedInput), run });\n this.#drainInputQueue().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n this.#activeAbort?.abort();\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n item?.run.emit({\n type: \"turn-error\",\n message: sessionKilledError().message,\n });\n item?.run.close();\n }\n }\n\n async #ensureLoaded(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n this.#loadPromise ??= this.#loadSessionState();\n try {\n await this.#loadPromise;\n } catch (error) {\n this.#loadPromise = undefined;\n throw error;\n }\n }\n\n async #loadSessionState(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n await this.#replaceWithStoredSession();\n this.#loaded = true;\n }\n\n async #replaceWithStoredSession(): Promise<void> {\n const stored = await this.#persistence.store.load(this.#persistence.key);\n this.#storeVersion = stored?.version;\n this.#history = new AgentModelHistory(decodeStoredSessionSnapshot(stored));\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await this.#processQueuedInput(item);\n }\n }\n } finally {\n this.#running = false;\n }\n }\n\n async #processQueuedInput({ input, run }: QueuedInput): Promise<void> {\n this.#activeAbort = new AbortController();\n const historySnapshot = this.#history.modelSnapshot();\n\n try {\n run.emit({ type: \"turn-start\" });\n this.#history.appendUserInput(input);\n await this.#commitHistory();\n\n const result = await runAgentLoop({\n emit: (event) => run.emit(event),\n history: this.#history,\n llm: this.#llm,\n signal: this.#activeAbort.signal,\n });\n\n await this.#commitHistory();\n run.emit({ type: result === \"aborted\" ? \"turn-abort\" : \"turn-end\" });\n } catch (error) {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n return;\n }\n\n this.#history.rollback(historySnapshot);\n try {\n await this.#commitHistory();\n } catch (rollbackError) {\n run.emit({\n type: \"turn-error\",\n message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(\n rollbackError\n )}`,\n });\n return;\n }\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n } finally {\n run.close();\n this.#activeAbort = undefined;\n }\n }\n\n async #commitHistory(): Promise<void> {\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n {\n state: encodeSessionSnapshot(this.#history.modelSnapshot()),\n version: this.#storeVersion,\n },\n { expectedVersion: this.#storeVersion ?? null }\n );\n\n if (!result.ok) {\n await this.#replaceWithStoredSession();\n throw new SessionCommitConflictError(this.#persistence.key);\n }\n\n this.#storeVersion = result.version;\n }\n}\n\nexport function normalizeAgentInput(input: AgentInput): UserInput {\n if (typeof input === \"string\") {\n return {\n type: \"user-text\",\n text: input,\n };\n }\n\n if (isStringArrayInput(input)) {\n return {\n type: \"user-text\",\n text: structuredClone(input) as readonly string[],\n };\n }\n\n if (isArrayInput(input)) {\n assertUserMessageContent(input);\n return {\n type: \"user-message\",\n content: structuredClone(input) as readonly UserMessageContentPart[],\n };\n }\n\n if (isUserMessage(input)) {\n assertUserMessageContent(input.content);\n }\n\n return structuredClone(input);\n}\n\nfunction isStringArrayInput(input: AgentInput): input is readonly string[] {\n return isArrayInput(input) && input.every((part) => typeof part === \"string\");\n}\n\nfunction isArrayInput(\n input: AgentInput\n): input is readonly string[] | readonly UserMessageContentPart[] {\n return Array.isArray(input);\n}\n\nfunction isUserMessage(input: UserInput): input is UserMessage {\n return input.type === \"user-message\";\n}\n\nfunction assertUserMessageContent(\n input: readonly unknown[]\n): asserts input is readonly UserMessageContentPart[] {\n for (const part of input) {\n if (!isUserMessageContentPart(part)) {\n throw new TypeError(\n 'Agent input content parts must be { type: \"text\", text }, { type: \"image\", image }, or { type: \"file\", data, mediaType }.'\n );\n }\n }\n}\n\nfunction isUserMessageContentPart(\n part: unknown\n): part is UserMessageContentPart {\n if (part === null || typeof part !== \"object\" || !(\"type\" in part)) {\n return false;\n }\n\n if (part.type === \"text\") {\n return \"text\" in part && typeof part.text === \"string\";\n }\n\n if (part.type === \"image\") {\n return (\n \"image\" in part &&\n typeof part.image === \"string\" &&\n (!(\"mediaType\" in part) || typeof part.mediaType === \"string\")\n );\n }\n\n if (part.type === \"file\") {\n return (\n \"data\" in part &&\n isUserMessageFileData(part.data) &&\n \"mediaType\" in part &&\n typeof part.mediaType === \"string\" &&\n (!(\"filename\" in part) || typeof part.filename === \"string\")\n );\n }\n\n return false;\n}\n\nfunction isUserMessageFileData(data: unknown): boolean {\n if (typeof data === \"string\") {\n return true;\n }\n\n if (data === null || typeof data !== \"object\" || !(\"type\" in data)) {\n return false;\n }\n\n if (data.type === \"data\") {\n return \"data\" in data && typeof data.data === \"string\";\n }\n\n if (data.type === \"reference\") {\n return (\n \"reference\" in data &&\n data.reference !== null &&\n typeof data.reference === \"object\" &&\n Object.values(data.reference).every((value) => typeof value === \"string\")\n );\n }\n\n if (data.type === \"text\") {\n return \"text\" in data && typeof data.text === \"string\";\n }\n\n if (data.type === \"url\") {\n return \"url\" in data && typeof data.url === \"string\";\n }\n\n return false;\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nfunction sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nclass SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ //#region src/session/snapshot.ts
2
+ function encodeSessionSnapshot(history) {
3
+ return {
4
+ schemaVersion: 1,
5
+ history: structuredClone(history)
6
+ };
7
+ }
8
+ function decodeStoredSessionSnapshot(stored) {
9
+ if (!stored) return [];
10
+ const snapshot = stored.state;
11
+ if (isSessionSnapshotV1(snapshot)) return structuredClone(snapshot.history);
12
+ throw new Error("Unsupported stored session state");
13
+ }
14
+ function isSessionSnapshotV1(value) {
15
+ return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 1 && "history" in value && Array.isArray(value.history);
16
+ }
17
+ //#endregion
18
+ export { decodeStoredSessionSnapshot, encodeSessionSnapshot };
19
+
20
+ //# sourceMappingURL=snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"snapshot.js","names":[],"sources":["../../src/session/snapshot.ts"],"sourcesContent":["import type { AgentMessage } from \"../llm\";\nimport type { StoredSession } from \"./store/types\";\n\nexport interface AgentSessionSnapshotV1 {\n readonly history: AgentMessage[];\n readonly schemaVersion: 1;\n}\n\nexport type AgentSessionSnapshot = AgentSessionSnapshotV1;\n\nexport function encodeSessionSnapshot(\n history: AgentMessage[]\n): AgentSessionSnapshot {\n return { schemaVersion: 1, history: structuredClone(history) };\n}\n\nexport function decodeStoredSessionSnapshot(\n stored: StoredSession | null\n): AgentMessage[] {\n if (!stored) {\n return [];\n }\n\n const snapshot = stored.state;\n if (isSessionSnapshotV1(snapshot)) {\n return structuredClone(snapshot.history);\n }\n\n throw new Error(\"Unsupported stored session state\");\n}\n\nfunction isSessionSnapshotV1(value: unknown): value is AgentSessionSnapshotV1 {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"schemaVersion\" in value &&\n value.schemaVersion === 1 &&\n \"history\" in value &&\n Array.isArray(value.history)\n );\n}\n"],"mappings":";AAUA,SAAgB,sBACd,SACsB;CACtB,OAAO;EAAE,eAAe;EAAG,SAAS,gBAAgB,OAAO;CAAE;AAC/D;AAEA,SAAgB,4BACd,QACgB;CAChB,IAAI,CAAC,QACH,OAAO,CAAC;CAGV,MAAM,WAAW,OAAO;CACxB,IAAI,oBAAoB,QAAQ,GAC9B,OAAO,gBAAgB,SAAS,OAAO;CAGzC,MAAM,IAAI,MAAM,kCAAkC;AACpD;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO;AAE/B"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@minpeter/pss-runtime",
3
- "version": "0.0.5",
3
+ "version": "0.0.6",
4
4
  "description": "Generic agent runtime for sessions, model loops, and event streams.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",