@anvia/studio 0.1.0 → 0.1.1

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/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Message, JsonObject, AgentTraceOptions, PromptResponse, AgentStreamEvent, JsonValue, Usage, AgentTraceInfo, Agent, AgentObserver, AgentRunStartArgs, AgentRunObserver } from '@anvia/core';
1
+ import { Message, JsonObject, AgentTraceOptions, PromptResponse, AgentStreamEvent, JsonValue, Usage, AgentTraceInfo, Agent, MemoryStore, AgentObserver, AgentRunStartArgs, AgentRunObserver } from '@anvia/core';
2
2
  import { Hono } from 'hono';
3
3
 
4
4
  type StudioCapability = "agents" | "approvals" | "knowledge" | "observability" | "sessions" | "traces";
@@ -80,18 +80,21 @@ type StudioSessionListOptions = {
80
80
  agentId?: string;
81
81
  limit: number;
82
82
  };
83
- type StudioSessionAppendInput = {
83
+ type StudioSessionRunStatus = "running" | "success" | "error";
84
+ type StudioSessionRunTranscriptInput = {
84
85
  id: string;
86
+ runId: string;
85
87
  title?: string;
86
- messages: Message[];
87
88
  transcript: StudioTranscriptEntry[];
89
+ status: StudioSessionRunStatus;
90
+ error?: JsonValue;
88
91
  };
89
- type StudioSessionStore = {
92
+ type StudioSessionStore = MemoryStore & {
90
93
  readonly kind?: string;
91
94
  listSessions(options: StudioSessionListOptions): StudioSessionSummary[] | Promise<StudioSessionSummary[]>;
92
95
  createSession(input: StudioSessionCreateInput): StudioSessionSummary | Promise<StudioSessionSummary>;
93
96
  getSession(id: string): StudioSession | undefined | Promise<StudioSession | undefined>;
94
- appendSessionRun(input: StudioSessionAppendInput): StudioSession | undefined | Promise<StudioSession | undefined>;
97
+ saveSessionRunTranscript(input: StudioSessionRunTranscriptInput): StudioSession | undefined | Promise<StudioSession | undefined>;
95
98
  deleteSession?(id: string): boolean | Promise<boolean>;
96
99
  };
97
100
  type StudioTraceStatus = "running" | "success" | "error";
@@ -341,4 +344,4 @@ type SqliteSessionStoreOptions = {
341
344
  };
342
345
  declare function createSqliteSessionStore(options?: SqliteSessionStoreOptions): StudioSessionStore & StudioTraceStore;
343
346
 
344
- export { type AgentRunRequest, type AgentRunResponse, type AgentRunStreamEvent, type AnviaStudio, type SqliteSessionStoreOptions, Studio, type StudioAgent, type StudioAgentConfig, type StudioAgentKnowledgeConfig, type StudioCapability, type StudioCapabilityConfig, type StudioConfig, type StudioErrorCode, type StudioErrorResponse, type StudioKnowledgeEvidence, type StudioKnowledgeEvidenceDocument, type StudioKnowledgeSourceKind, type StudioKnowledgeSourceSummary, type StudioKnowledgeSummary, type StudioOptions, type StudioServeOptions, type StudioSession, type StudioSessionAppendInput, type StudioSessionCreateInput, type StudioSessionListOptions, type StudioSessionStore, type StudioSessionSummary, type StudioSessionTraceListOptions, type StudioStaticKnowledgeDocument, type StudioStores, type StudioToolApproval, type StudioToolApprovalDecision, type StudioToolApprovalRequestEvent, type StudioToolApprovalResultEvent, type StudioToolApprovalStatus, type StudioToolApprovalTranscript, type StudioToolQuestion, type StudioToolQuestionAnswer, type StudioToolQuestionChoice, type StudioToolQuestionPrompt, type StudioToolQuestionRequestEvent, type StudioToolQuestionResultEvent, type StudioToolQuestionStatus, type StudioToolQuestionTranscript, type StudioTrace, type StudioTraceListOptions, type StudioTraceObservation, type StudioTraceObservationKind, StudioTraceObserver, type StudioTraceObserverOptions, type StudioTraceStatus, type StudioTraceStore, type StudioTraceSummary, type StudioTranscriptChatEntry, type StudioTranscriptEntry, type StudioTranscriptReasoningEntry, type StudioTranscriptToolEntry, type StudioUiOptions, createSqliteSessionStore };
347
+ export { type AgentRunRequest, type AgentRunResponse, type AgentRunStreamEvent, type AnviaStudio, type SqliteSessionStoreOptions, Studio, type StudioAgent, type StudioAgentConfig, type StudioAgentKnowledgeConfig, type StudioCapability, type StudioCapabilityConfig, type StudioConfig, type StudioErrorCode, type StudioErrorResponse, type StudioKnowledgeEvidence, type StudioKnowledgeEvidenceDocument, type StudioKnowledgeSourceKind, type StudioKnowledgeSourceSummary, type StudioKnowledgeSummary, type StudioOptions, type StudioServeOptions, type StudioSession, type StudioSessionCreateInput, type StudioSessionListOptions, type StudioSessionRunStatus, type StudioSessionRunTranscriptInput, type StudioSessionStore, type StudioSessionSummary, type StudioSessionTraceListOptions, type StudioStaticKnowledgeDocument, type StudioStores, type StudioToolApproval, type StudioToolApprovalDecision, type StudioToolApprovalRequestEvent, type StudioToolApprovalResultEvent, type StudioToolApprovalStatus, type StudioToolApprovalTranscript, type StudioToolQuestion, type StudioToolQuestionAnswer, type StudioToolQuestionChoice, type StudioToolQuestionPrompt, type StudioToolQuestionRequestEvent, type StudioToolQuestionResultEvent, type StudioToolQuestionStatus, type StudioToolQuestionTranscript, type StudioTrace, type StudioTraceListOptions, type StudioTraceObservation, type StudioTraceObservationKind, StudioTraceObserver, type StudioTraceObserverOptions, type StudioTraceStatus, type StudioTraceStore, type StudioTraceSummary, type StudioTranscriptChatEntry, type StudioTranscriptEntry, type StudioTranscriptReasoningEntry, type StudioTranscriptToolEntry, type StudioUiOptions, createSqliteSessionStore };
package/dist/index.js CHANGED
@@ -1,7 +1,9 @@
1
1
  // src/runtime/studio.ts
2
2
  import {
3
3
  Agent,
4
- createHook as createHook3
4
+ createHook as createHook3,
5
+ Message,
6
+ resolveMemoryOptions
5
7
  } from "@anvia/core";
6
8
  import { serve } from "@hono/node-server";
7
9
  import { Hono as HonoApp } from "hono";
@@ -544,15 +546,14 @@ var SqliteSessionStore = class {
544
546
  };
545
547
  }
546
548
  getSession(id) {
547
- const db = this.database();
548
- const row = db.prepare(
549
- `SELECT id, agent_id, title, metadata_json, messages_json, transcript_json, created_at, updated_at
550
- FROM runner_sessions
551
- WHERE id = $id`
552
- ).get({ $id: id });
553
- return row === void 0 ? void 0 : toSession(row);
549
+ const row = this.getSessionRow(id);
550
+ return row === void 0 ? void 0 : toSession(row, this.listSessionRunRows(id));
554
551
  }
555
- appendSessionRun(input) {
552
+ load(context) {
553
+ const session = this.getSession(context.sessionId);
554
+ return Promise.resolve(session?.messages ?? []);
555
+ }
556
+ append(input) {
556
557
  const db = this.database();
557
558
  try {
558
559
  db.exec("BEGIN IMMEDIATE");
@@ -560,39 +561,132 @@ var SqliteSessionStore = class {
560
561
  `SELECT id, agent_id, title, metadata_json, messages_json, transcript_json, created_at, updated_at
561
562
  FROM runner_sessions
562
563
  WHERE id = $id`
563
- ).get({ $id: input.id });
564
+ ).get({ $id: input.context.sessionId });
564
565
  if (row === void 0) {
565
566
  db.exec("ROLLBACK");
566
- return void 0;
567
+ return Promise.resolve();
567
568
  }
568
569
  const current = toSession(row);
569
570
  const messages = [...current.messages, ...input.messages];
570
- const transcript = renumberTranscript([...current.transcript, ...input.transcript]);
571
- const title = current.title ?? input.title;
572
571
  const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
572
+ db.prepare(
573
+ `UPDATE runner_sessions
574
+ SET messages_json = $messages,
575
+ updated_at = $updatedAt
576
+ WHERE id = $id`
577
+ ).run({
578
+ $id: input.context.sessionId,
579
+ $messages: JSON.stringify(messages),
580
+ $updatedAt: updatedAt
581
+ });
582
+ db.exec("COMMIT");
583
+ return Promise.resolve();
584
+ } catch (error) {
585
+ if (db.isTransaction) {
586
+ db.exec("ROLLBACK");
587
+ }
588
+ throw error;
589
+ }
590
+ }
591
+ clear(context) {
592
+ const db = this.database();
593
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
594
+ try {
595
+ db.exec("BEGIN IMMEDIATE");
596
+ db.prepare(
597
+ `UPDATE runner_sessions
598
+ SET messages_json = '[]',
599
+ transcript_json = '[]',
600
+ updated_at = $updatedAt
601
+ WHERE id = $id`
602
+ ).run({
603
+ $id: context.sessionId,
604
+ $updatedAt: updatedAt
605
+ });
606
+ db.prepare("DELETE FROM runner_session_runs WHERE session_id = $id").run({
607
+ $id: context.sessionId
608
+ });
609
+ db.exec("COMMIT");
610
+ return Promise.resolve();
611
+ } catch (error) {
612
+ if (db.isTransaction) {
613
+ db.exec("ROLLBACK");
614
+ }
615
+ throw error;
616
+ }
617
+ }
618
+ async recordError(input) {
619
+ const runId = studioRunId(input.context) ?? input.runId;
620
+ const existing = this.getSessionRun(input.context.sessionId, runId);
621
+ const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessagesFallback(input.messages) : parseJsonArray(existing.transcript_json);
622
+ await this.saveSessionRunTranscript({
623
+ id: input.context.sessionId,
624
+ runId,
625
+ transcript,
626
+ status: "error",
627
+ error: serializeJsonError(input.error)
628
+ });
629
+ }
630
+ saveSessionRunTranscript(input) {
631
+ const db = this.database();
632
+ const now = (/* @__PURE__ */ new Date()).toISOString();
633
+ try {
634
+ db.exec("BEGIN IMMEDIATE");
635
+ const row = this.getSessionRow(input.id);
636
+ if (row === void 0) {
637
+ db.exec("ROLLBACK");
638
+ return void 0;
639
+ }
640
+ const current = toSession(row, this.listSessionRunRows(input.id));
641
+ const title = current.title ?? input.title;
642
+ db.prepare(
643
+ `INSERT INTO runner_session_runs (
644
+ run_id,
645
+ session_id,
646
+ status,
647
+ title,
648
+ transcript_json,
649
+ error_json,
650
+ created_at,
651
+ updated_at
652
+ ) VALUES (
653
+ $runId,
654
+ $sessionId,
655
+ $status,
656
+ $title,
657
+ $transcript,
658
+ $error,
659
+ $now,
660
+ $now
661
+ )
662
+ ON CONFLICT(run_id) DO UPDATE SET
663
+ status = excluded.status,
664
+ title = COALESCE(runner_session_runs.title, excluded.title),
665
+ transcript_json = excluded.transcript_json,
666
+ error_json = excluded.error_json,
667
+ updated_at = excluded.updated_at`
668
+ ).run({
669
+ $runId: input.runId,
670
+ $sessionId: input.id,
671
+ $status: input.status,
672
+ $title: input.title ?? null,
673
+ $transcript: JSON.stringify(renumberTranscript(input.transcript)),
674
+ $error: input.error === void 0 ? null : JSON.stringify(input.error),
675
+ $now: now
676
+ });
573
677
  db.prepare(
574
678
  `UPDATE runner_sessions
575
679
  SET title = $title,
576
- messages_json = $messages,
577
- transcript_json = $transcript,
578
680
  updated_at = $updatedAt
579
681
  WHERE id = $id`
580
682
  ).run({
581
683
  $id: input.id,
582
684
  $title: title ?? null,
583
- $messages: JSON.stringify(messages),
584
- $transcript: JSON.stringify(transcript),
585
- $updatedAt: updatedAt
685
+ $updatedAt: now
586
686
  });
587
687
  db.exec("COMMIT");
588
- return {
589
- ...current,
590
- ...title === void 0 ? {} : { title },
591
- updatedAt,
592
- messageCount: messages.length,
593
- messages,
594
- transcript
595
- };
688
+ const updated = this.getSession(input.id);
689
+ return updated;
596
690
  } catch (error) {
597
691
  if (db.isTransaction) {
598
692
  db.exec("ROLLBACK");
@@ -605,6 +699,7 @@ var SqliteSessionStore = class {
605
699
  try {
606
700
  db.exec("BEGIN IMMEDIATE");
607
701
  db.prepare("DELETE FROM runner_traces WHERE session_id = $id").run({ $id: id });
702
+ db.prepare("DELETE FROM runner_session_runs WHERE session_id = $id").run({ $id: id });
608
703
  const result = db.prepare("DELETE FROM runner_sessions WHERE id = $id").run({ $id: id });
609
704
  db.exec("COMMIT");
610
705
  return Number(result.changes) > 0;
@@ -765,6 +860,19 @@ var SqliteSessionStore = class {
765
860
  ) STRICT;
766
861
  CREATE INDEX IF NOT EXISTS runner_sessions_agent_updated_idx
767
862
  ON runner_sessions(agent_id, updated_at DESC);
863
+ CREATE TABLE IF NOT EXISTS runner_session_runs (
864
+ run_id TEXT PRIMARY KEY,
865
+ session_id TEXT NOT NULL,
866
+ status TEXT NOT NULL,
867
+ title TEXT,
868
+ transcript_json TEXT NOT NULL,
869
+ error_json TEXT,
870
+ created_at TEXT NOT NULL,
871
+ updated_at TEXT NOT NULL,
872
+ FOREIGN KEY(session_id) REFERENCES runner_sessions(id) ON DELETE CASCADE
873
+ ) STRICT;
874
+ CREATE INDEX IF NOT EXISTS runner_session_runs_session_created_idx
875
+ ON runner_session_runs(session_id, created_at ASC);
768
876
  CREATE TABLE IF NOT EXISTS runner_traces (
769
877
  id TEXT PRIMARY KEY,
770
878
  session_id TEXT NOT NULL,
@@ -787,13 +895,39 @@ var SqliteSessionStore = class {
787
895
  this.db = db;
788
896
  return db;
789
897
  }
898
+ getSessionRow(id) {
899
+ return this.database().prepare(
900
+ `SELECT id, agent_id, title, metadata_json, messages_json, transcript_json, created_at, updated_at
901
+ FROM runner_sessions
902
+ WHERE id = $id`
903
+ ).get({ $id: id });
904
+ }
905
+ getSessionRun(sessionId, runId) {
906
+ return this.database().prepare(
907
+ `SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
908
+ FROM runner_session_runs
909
+ WHERE session_id = $sessionId AND run_id = $runId`
910
+ ).get({ $sessionId: sessionId, $runId: runId });
911
+ }
912
+ listSessionRunRows(sessionId) {
913
+ return this.database().prepare(
914
+ `SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
915
+ FROM runner_session_runs
916
+ WHERE session_id = $sessionId
917
+ ORDER BY created_at ASC`
918
+ ).all({ $sessionId: sessionId });
919
+ }
790
920
  };
791
- function toSession(row) {
921
+ function toSession(row, runRows = []) {
792
922
  const summary = toSessionSummary(row);
923
+ const legacyTranscript = parseJsonArray(row.transcript_json);
924
+ const runTranscript = runRows.flatMap(
925
+ (runRow) => parseJsonArray(runRow.transcript_json)
926
+ );
793
927
  return {
794
928
  ...summary,
795
929
  messages: parseJsonArray(row.messages_json),
796
- transcript: renumberTranscript(parseJsonArray(row.transcript_json))
930
+ transcript: renumberTranscript([...legacyTranscript, ...runTranscript])
797
931
  };
798
932
  }
799
933
  function toSessionSummary(row) {
@@ -852,6 +986,96 @@ function parseJsonValue(value) {
852
986
  function renumberTranscript(entries) {
853
987
  return entries.map((entry, entryId) => ({ ...entry, entryId }));
854
988
  }
989
+ function studioRunId(context) {
990
+ const value = context.metadata?.studioRunId;
991
+ return typeof value === "string" && value.length > 0 ? value : void 0;
992
+ }
993
+ function serializeJsonError(error) {
994
+ if (error instanceof Error) {
995
+ return {
996
+ name: error.name,
997
+ message: error.message
998
+ };
999
+ }
1000
+ if (error === null || typeof error === "string" || typeof error === "number" || typeof error === "boolean") {
1001
+ return error;
1002
+ }
1003
+ return String(error);
1004
+ }
1005
+ function transcriptFromMessagesFallback(messages) {
1006
+ const transcript = [];
1007
+ for (const message of messages) {
1008
+ if (message.role === "system") {
1009
+ continue;
1010
+ }
1011
+ if (message.role === "user") {
1012
+ for (const content of message.content) {
1013
+ if (content.type === "text") {
1014
+ transcript.push({
1015
+ entryId: transcript.length,
1016
+ kind: "message",
1017
+ role: "user",
1018
+ text: content.text
1019
+ });
1020
+ }
1021
+ }
1022
+ continue;
1023
+ }
1024
+ if (message.role === "tool") {
1025
+ for (const content of message.content) {
1026
+ transcript.push({
1027
+ entryId: transcript.length,
1028
+ kind: "tool",
1029
+ toolName: "tool_result",
1030
+ callId: content.callId ?? content.id,
1031
+ result: content.content.map((item) => "text" in item ? item.text : "[image]").join("\n")
1032
+ });
1033
+ }
1034
+ continue;
1035
+ }
1036
+ for (const content of message.content) {
1037
+ if (content.type === "text") {
1038
+ appendAssistantTranscriptText(transcript, content.text);
1039
+ } else if (content.type === "reasoning") {
1040
+ transcript.push({
1041
+ entryId: transcript.length,
1042
+ kind: "reasoning",
1043
+ ...content.id === void 0 ? {} : { reasoningId: content.id },
1044
+ text: content.text
1045
+ });
1046
+ } else if (content.type === "tool_call") {
1047
+ transcript.push({
1048
+ entryId: transcript.length,
1049
+ kind: "tool",
1050
+ toolName: content.function.name,
1051
+ callId: content.callId ?? content.id,
1052
+ args: formatJson(content.function.arguments)
1053
+ });
1054
+ }
1055
+ }
1056
+ }
1057
+ return transcript;
1058
+ }
1059
+ function appendAssistantTranscriptText(transcript, text) {
1060
+ const last = transcript.at(-1);
1061
+ if (last?.kind === "message" && last.role === "assistant") {
1062
+ last.text = `${last.text}${text}`;
1063
+ return;
1064
+ }
1065
+ transcript.push({
1066
+ entryId: transcript.length,
1067
+ kind: "message",
1068
+ role: "assistant",
1069
+ text
1070
+ });
1071
+ }
1072
+ function formatJson(value) {
1073
+ try {
1074
+ return JSON.stringify(value, null, 2);
1075
+ } catch {
1076
+ return String(value);
1077
+ }
1078
+ }
855
1079
 
856
1080
  // src/runtime/shared.ts
857
1081
  function resolveStores(options) {
@@ -1823,22 +2047,42 @@ function traceForRun(trace, agentId, session) {
1823
2047
  ...trace?.sessionId !== void 0 ? { sessionId: trace.sessionId } : session === void 0 ? {} : { sessionId: session.id }
1824
2048
  };
1825
2049
  }
1826
- async function* persistStreamingSessionRun(props) {
2050
+ async function* persistStreamingSessionTranscript(props) {
1827
2051
  const transcript = [messageToTranscriptEntry(props.message, 0)];
1828
- for await (const event of props.stream) {
1829
- acceptTranscriptStreamEvent(transcript, event);
1830
- if (event.type === "final") {
1831
- const nextSession = await props.store.appendSessionRun({
2052
+ const title = optionalTitle(props.message);
2053
+ await props.store.saveSessionRunTranscript({
2054
+ id: props.session.id,
2055
+ runId: props.runId,
2056
+ ...title,
2057
+ transcript,
2058
+ status: "running"
2059
+ });
2060
+ try {
2061
+ for await (const event of props.stream) {
2062
+ acceptTranscriptStreamEvent(transcript, event);
2063
+ const nextSession = await props.store.saveSessionRunTranscript({
1832
2064
  id: props.session.id,
1833
- ...optionalTitle(props.message),
1834
- messages: event.messages,
1835
- transcript
2065
+ runId: props.runId,
2066
+ ...title,
2067
+ transcript,
2068
+ status: event.type === "final" ? "success" : event.type === "error" ? "error" : "running",
2069
+ ...event.type === "error" ? { error: serializeError2(event.error) } : {}
1836
2070
  });
1837
2071
  if (nextSession === void 0) {
1838
2072
  throw new Error("Session not found");
1839
2073
  }
2074
+ yield event;
1840
2075
  }
1841
- yield event;
2076
+ } catch (error) {
2077
+ await props.store.saveSessionRunTranscript({
2078
+ id: props.session.id,
2079
+ runId: props.runId,
2080
+ ...title,
2081
+ transcript,
2082
+ status: "error",
2083
+ error: serializeError2(error)
2084
+ });
2085
+ throw error;
1842
2086
  }
1843
2087
  }
1844
2088
  function acceptTranscriptStreamEvent(transcript, event) {
@@ -1854,7 +2098,7 @@ function acceptTranscriptStreamEvent(transcript, event) {
1854
2098
  kind: "tool",
1855
2099
  toolName: event.toolCall.function.name,
1856
2100
  callId: event.toolCall.callId ?? event.toolCall.id,
1857
- args: formatJson(event.toolCall.function.arguments)
2101
+ args: formatJson2(event.toolCall.function.arguments)
1858
2102
  });
1859
2103
  }
1860
2104
  if (event.type === "tool_result") {
@@ -1987,7 +2231,7 @@ function transcriptFromMessages(messages) {
1987
2231
  kind: "tool",
1988
2232
  toolName: content.function.name,
1989
2233
  callId: content.callId ?? content.id,
1990
- args: formatJson(content.function.arguments)
2234
+ args: formatJson2(content.function.arguments)
1991
2235
  });
1992
2236
  }
1993
2237
  }
@@ -2073,7 +2317,7 @@ function extractMessageText(message) {
2073
2317
  return [item.text];
2074
2318
  }
2075
2319
  if (item.type === "tool_call") {
2076
- return [`${item.function.name}(${formatJson(item.function.arguments)})`];
2320
+ return [`${item.function.name}(${formatJson2(item.function.arguments)})`];
2077
2321
  }
2078
2322
  if (item.type === "tool_result") {
2079
2323
  return item.content.map((result) => "text" in result ? result.text : "[image]");
@@ -2081,7 +2325,7 @@ function extractMessageText(message) {
2081
2325
  return [];
2082
2326
  }).join("\n");
2083
2327
  }
2084
- function formatJson(value) {
2328
+ function formatJson2(value) {
2085
2329
  try {
2086
2330
  return JSON.stringify(value, null, 2);
2087
2331
  } catch {
@@ -2408,9 +2652,7 @@ function agentMetadata(agent) {
2408
2652
  }
2409
2653
  function createStudioApp(options) {
2410
2654
  const stores = resolveStores(options);
2411
- const agents = normalizeAgents(options.agents).map(
2412
- (agent) => withStudioTraceObserver(agent, stores.traces)
2413
- );
2655
+ const agents = normalizeAgents(options.agents).map((agent) => withStudioSessionMemory(agent, stores.sessions)).map((agent) => withStudioTraceObserver(agent, stores.traces));
2414
2656
  const agentMap = new Map(agents.map((agent) => [agent.id, agent]));
2415
2657
  const approvalRuntime = createApprovalRuntime();
2416
2658
  const questionRuntime = createQuestionRuntime();
@@ -2469,12 +2711,14 @@ function createStudioApp(options) {
2469
2711
  return errorResponse(c, 400, "bad_request", "Session belongs to another agent");
2470
2712
  }
2471
2713
  const runId = globalThis.crypto.randomUUID();
2472
- const request = agent.agent.prompt(body.message);
2473
- if (session !== void 0) {
2474
- request.withHistory(session.messages);
2475
- } else if (body.history !== void 0) {
2476
- request.withHistory(body.history);
2477
- }
2714
+ const memoryMetadata = {
2715
+ agentId,
2716
+ ...body.metadata ?? {},
2717
+ studioRunId: runId
2718
+ };
2719
+ const request = session !== void 0 ? agent.agent.session(session.id, { metadata: memoryMetadata }).prompt(body.message) : agent.agent.prompt(
2720
+ body.history !== void 0 ? [...body.history, normalizePromptMessage(body.message)] : body.message
2721
+ );
2478
2722
  if (body.maxTurns !== void 0) {
2479
2723
  request.maxTurns(body.maxTurns);
2480
2724
  }
@@ -2512,11 +2756,12 @@ function createStudioApp(options) {
2512
2756
  request.requestHook(effectiveHook);
2513
2757
  }
2514
2758
  const runStream = mergeRunAndApprovalEvents(request.stream(), runtimeEvents);
2515
- const stream = session === void 0 || stores.sessions === void 0 ? runStream : persistStreamingSessionRun({
2759
+ const stream = session === void 0 || stores.sessions === void 0 ? runStream : persistStreamingSessionTranscript({
2516
2760
  stream: runStream,
2517
2761
  store: stores.sessions,
2518
2762
  session,
2519
- message: body.message
2763
+ message: body.message,
2764
+ runId
2520
2765
  });
2521
2766
  return streamAgentRunEvents(c, stream);
2522
2767
  }
@@ -2544,15 +2789,30 @@ function createStudioApp(options) {
2544
2789
  }
2545
2790
  const response = await request.send();
2546
2791
  if (session !== void 0 && stores.sessions !== void 0) {
2547
- await stores.sessions.appendSessionRun({
2792
+ await stores.sessions.saveSessionRunTranscript({
2548
2793
  id: session.id,
2794
+ runId,
2549
2795
  ...optionalTitle(body.message),
2550
- messages: response.messages,
2551
- transcript: transcriptFromMessages(response.messages)
2796
+ transcript: transcriptFromMessages(response.messages),
2797
+ status: "success"
2552
2798
  });
2553
2799
  }
2554
2800
  return c.json(response);
2555
2801
  } catch (error) {
2802
+ if (session !== void 0 && stores.sessions !== void 0) {
2803
+ const messages = await stores.sessions.load({
2804
+ sessionId: session.id,
2805
+ metadata: memoryMetadata
2806
+ });
2807
+ await stores.sessions.saveSessionRunTranscript({
2808
+ id: session.id,
2809
+ runId,
2810
+ ...optionalTitle(body.message),
2811
+ transcript: transcriptFromMessages(messages.slice(session.messageCount)),
2812
+ status: "error",
2813
+ error: serializeError2(error)
2814
+ });
2815
+ }
2556
2816
  return errorResponse(c, 500, "internal_error", "Agent run failed", serializeError2(error));
2557
2817
  }
2558
2818
  });
@@ -2584,36 +2844,60 @@ function createStudioApp(options) {
2584
2844
  ...stores.traces === void 0 ? {} : { traceStore: stores.traces }
2585
2845
  };
2586
2846
  }
2847
+ function normalizePromptMessage(message) {
2848
+ return typeof message === "string" ? Message.user(message) : message;
2849
+ }
2850
+ function withStudioSessionMemory(studioAgent, sessionStore) {
2851
+ if (sessionStore === void 0) {
2852
+ return studioAgent;
2853
+ }
2854
+ return {
2855
+ ...studioAgent,
2856
+ agent: cloneAgent(studioAgent.agent, {
2857
+ memory: {
2858
+ store: sessionStore,
2859
+ options: resolveMemoryOptions({ savePolicy: "message" })
2860
+ }
2861
+ })
2862
+ };
2863
+ }
2587
2864
  function withStudioTraceObserver(studioAgent, traceStore) {
2588
2865
  if (traceStore === void 0 || hasStudioTraceObserver(studioAgent.agent)) {
2589
2866
  return studioAgent;
2590
2867
  }
2591
2868
  return {
2592
2869
  ...studioAgent,
2593
- agent: new Agent({
2594
- id: studioAgent.agent.id,
2595
- name: studioAgent.agent.name,
2596
- description: studioAgent.agent.description,
2597
- model: studioAgent.agent.model,
2598
- instructions: studioAgent.agent.instructions,
2599
- staticContext: studioAgent.agent.staticContext,
2600
- temperature: studioAgent.agent.temperature,
2601
- maxTokens: studioAgent.agent.maxTokens,
2602
- additionalParams: studioAgent.agent.additionalParams,
2603
- toolSet: studioAgent.agent.toolSet,
2604
- toolChoice: studioAgent.agent.toolChoice,
2605
- defaultMaxTurns: studioAgent.agent.defaultMaxTurns,
2606
- hook: studioAgent.agent.hook,
2607
- outputSchema: studioAgent.agent.outputSchema,
2870
+ agent: cloneAgent(studioAgent.agent, {
2608
2871
  observers: [
2609
2872
  ...studioAgent.agent.observers,
2610
2873
  { observer: new StudioTraceObserver({ store: traceStore }) }
2611
- ],
2612
- dynamicContexts: studioAgent.agent.dynamicContexts,
2613
- dynamicTools: studioAgent.agent.dynamicTools
2874
+ ]
2614
2875
  })
2615
2876
  };
2616
2877
  }
2878
+ function cloneAgent(agent, overrides = {}) {
2879
+ return new Agent({
2880
+ id: agent.id,
2881
+ name: agent.name,
2882
+ description: agent.description,
2883
+ model: agent.model,
2884
+ instructions: agent.instructions,
2885
+ staticContext: agent.staticContext,
2886
+ temperature: agent.temperature,
2887
+ maxTokens: agent.maxTokens,
2888
+ additionalParams: agent.additionalParams,
2889
+ toolSet: agent.toolSet,
2890
+ toolChoice: agent.toolChoice,
2891
+ defaultMaxTurns: agent.defaultMaxTurns,
2892
+ hook: agent.hook,
2893
+ outputSchema: agent.outputSchema,
2894
+ observers: agent.observers,
2895
+ dynamicContexts: agent.dynamicContexts,
2896
+ dynamicTools: agent.dynamicTools,
2897
+ memory: agent.memory,
2898
+ ...overrides
2899
+ });
2900
+ }
2617
2901
  function hasStudioTraceObserver(agent) {
2618
2902
  return agent.observers.some(
2619
2903
  (registration) => registration.observer instanceof StudioTraceObserver