@anvia/studio 0.1.0 → 0.1.2
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 +32 -7
- package/dist/index.js +702 -105
- package/dist/index.js.map +1 -1
- package/dist/ui/assets/{index-DArq3ZFi.js → index-Dy72BB4f.js} +6 -6
- package/dist/ui/assets/{index-DArq3ZFi.js.map → index-Dy72BB4f.js.map} +1 -1
- package/dist/ui/index.html +1 -1
- package/package.json +2 -2
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";
|
|
@@ -77,34 +79,38 @@ var StudioRunTraceObserver = class {
|
|
|
77
79
|
}
|
|
78
80
|
startTool(args) {
|
|
79
81
|
const startedAt = /* @__PURE__ */ new Date();
|
|
82
|
+
const childTrace = new ChildAgentToolTraceAccumulator(args);
|
|
80
83
|
return {
|
|
84
|
+
streamEvent: (streamArgs) => {
|
|
85
|
+
childTrace.accept(streamArgs);
|
|
86
|
+
},
|
|
81
87
|
end: (endArgs) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
);
|
|
88
|
+
const parentObservation = traceObservation({
|
|
89
|
+
kind: "tool",
|
|
90
|
+
name: args.toolName,
|
|
91
|
+
status: "success",
|
|
92
|
+
turn: args.turn,
|
|
93
|
+
startedAt,
|
|
94
|
+
input: parseOrString(args.args),
|
|
95
|
+
output: parseOrString(endArgs.result),
|
|
96
|
+
metadata: toolMetadata(args, endArgs.skipped)
|
|
97
|
+
});
|
|
98
|
+
this.observations.push(parentObservation);
|
|
99
|
+
this.observations.push(...childTrace.observations(parentObservation.id));
|
|
94
100
|
},
|
|
95
101
|
error: (errorArgs) => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
);
|
|
102
|
+
const parentObservation = traceObservation({
|
|
103
|
+
kind: "tool",
|
|
104
|
+
name: args.toolName,
|
|
105
|
+
status: "error",
|
|
106
|
+
turn: args.turn,
|
|
107
|
+
startedAt,
|
|
108
|
+
input: parseOrString(args.args),
|
|
109
|
+
error: serializeError(errorArgs.error),
|
|
110
|
+
metadata: toolMetadata(args, false)
|
|
111
|
+
});
|
|
112
|
+
this.observations.push(parentObservation);
|
|
113
|
+
this.observations.push(...childTrace.observations(parentObservation.id));
|
|
108
114
|
}
|
|
109
115
|
};
|
|
110
116
|
}
|
|
@@ -155,10 +161,191 @@ var StudioRunTraceObserver = class {
|
|
|
155
161
|
await store.saveTrace(trace);
|
|
156
162
|
}
|
|
157
163
|
};
|
|
164
|
+
var ChildAgentToolTraceAccumulator = class {
|
|
165
|
+
constructor(parent) {
|
|
166
|
+
this.parent = parent;
|
|
167
|
+
}
|
|
168
|
+
parent;
|
|
169
|
+
agentStarts = /* @__PURE__ */ new Map();
|
|
170
|
+
generationStarts = /* @__PURE__ */ new Map();
|
|
171
|
+
toolStarts = [];
|
|
172
|
+
completedObservations = [];
|
|
173
|
+
accept(args) {
|
|
174
|
+
const wrapper = args.event;
|
|
175
|
+
const child = isRecord(wrapper.event) ? wrapper.event : void 0;
|
|
176
|
+
if (child === void 0) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
const agentId = wrapper.agentId;
|
|
180
|
+
const agentName = wrapper.agentName;
|
|
181
|
+
const childTurn = typeof child.turn === "number" ? child.turn : this.parent.turn;
|
|
182
|
+
if (!this.agentStarts.has(agentId)) {
|
|
183
|
+
this.agentStarts.set(agentId, {
|
|
184
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
185
|
+
agentId,
|
|
186
|
+
...agentName === void 0 ? {} : { agentName }
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (child.type === "turn_start") {
|
|
190
|
+
this.generationStarts.set(generationKey(agentId, childTurn), {
|
|
191
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
192
|
+
input: toJsonValue({
|
|
193
|
+
prompt: child.prompt,
|
|
194
|
+
history: child.history
|
|
195
|
+
}),
|
|
196
|
+
agentId,
|
|
197
|
+
...agentName === void 0 ? {} : { agentName },
|
|
198
|
+
childTurn
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
if (child.type === "turn_end") {
|
|
203
|
+
const key = generationKey(agentId, childTurn);
|
|
204
|
+
const start = this.generationStarts.get(key);
|
|
205
|
+
this.generationStarts.delete(key);
|
|
206
|
+
this.completedObservations.push(
|
|
207
|
+
traceObservation({
|
|
208
|
+
kind: "generation",
|
|
209
|
+
name: `${agentLabel(agentId, agentName)}.model.turn.${childTurn}`,
|
|
210
|
+
status: "success",
|
|
211
|
+
turn: this.parent.turn,
|
|
212
|
+
startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
|
|
213
|
+
...start?.input === void 0 ? {} : { input: start.input },
|
|
214
|
+
output: toJsonValue(child.response),
|
|
215
|
+
metadata: this.childMetadata(agentId, agentName, childTurn)
|
|
216
|
+
})
|
|
217
|
+
);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
if (child.type === "tool_call" && isRecord(child.toolCall)) {
|
|
221
|
+
const toolCall = child.toolCall;
|
|
222
|
+
const toolCallFunction = isRecord(toolCall.function) ? toolCall.function : void 0;
|
|
223
|
+
const toolName = typeof toolCallFunction?.name === "string" ? toolCallFunction.name : "tool";
|
|
224
|
+
const callId = typeof toolCall.callId === "string" ? toolCall.callId : typeof toolCall.id === "string" ? toolCall.id : void 0;
|
|
225
|
+
this.toolStarts.push({
|
|
226
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
227
|
+
agentId,
|
|
228
|
+
...agentName === void 0 ? {} : { agentName },
|
|
229
|
+
childTurn,
|
|
230
|
+
toolName,
|
|
231
|
+
...callId === void 0 ? {} : { toolCallId: callId },
|
|
232
|
+
input: toJsonValue(toolCallFunction?.arguments ?? {}),
|
|
233
|
+
completed: false
|
|
234
|
+
});
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (child.type === "tool_result") {
|
|
238
|
+
const toolName = typeof child.toolName === "string" ? child.toolName : "tool";
|
|
239
|
+
const toolCallId = typeof child.toolCallId === "string" ? child.toolCallId : void 0;
|
|
240
|
+
const internalCallId = typeof child.internalCallId === "string" ? child.internalCallId : void 0;
|
|
241
|
+
const start = this.findToolStart(agentId, toolName, toolCallId);
|
|
242
|
+
const input = start?.input ?? (typeof child.args === "string" ? parseOrString(child.args) : void 0);
|
|
243
|
+
if (start !== void 0) {
|
|
244
|
+
start.completed = true;
|
|
245
|
+
}
|
|
246
|
+
this.completedObservations.push(
|
|
247
|
+
traceObservation({
|
|
248
|
+
kind: "tool",
|
|
249
|
+
name: `${agentLabel(agentId, agentName)}.${toolName}`,
|
|
250
|
+
status: "success",
|
|
251
|
+
turn: this.parent.turn,
|
|
252
|
+
startedAt: start?.startedAt ?? /* @__PURE__ */ new Date(),
|
|
253
|
+
...input === void 0 ? {} : { input },
|
|
254
|
+
...typeof child.result === "string" ? { output: parseOrString(child.result) } : {},
|
|
255
|
+
metadata: {
|
|
256
|
+
...this.childMetadata(agentId, agentName, childTurn),
|
|
257
|
+
...toolCallId === void 0 ? {} : { toolCallId },
|
|
258
|
+
...internalCallId === void 0 ? {} : { internalCallId }
|
|
259
|
+
}
|
|
260
|
+
})
|
|
261
|
+
);
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (child.type === "error") {
|
|
265
|
+
this.completedObservations.push(
|
|
266
|
+
traceObservation({
|
|
267
|
+
kind: "tool",
|
|
268
|
+
name: `${agentLabel(agentId, agentName)}.error`,
|
|
269
|
+
status: "error",
|
|
270
|
+
turn: this.parent.turn,
|
|
271
|
+
startedAt: /* @__PURE__ */ new Date(),
|
|
272
|
+
error: serializeError(child.error),
|
|
273
|
+
metadata: this.childMetadata(agentId, agentName, childTurn)
|
|
274
|
+
})
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
observations(parentObservationId) {
|
|
279
|
+
const observations = [];
|
|
280
|
+
const agentObservationIds = /* @__PURE__ */ new Map();
|
|
281
|
+
for (const agentStart of this.agentStarts.values()) {
|
|
282
|
+
const agentChildren = this.completedObservations.filter(
|
|
283
|
+
(observation) => isRecord(observation.metadata) && observation.metadata.childAgentId === agentStart.agentId
|
|
284
|
+
);
|
|
285
|
+
const childStartTimes = agentChildren.map((observation) => Date.parse(observation.startedAt));
|
|
286
|
+
const childEndTimes = agentChildren.map(
|
|
287
|
+
(observation) => Date.parse(observation.endedAt ?? observation.startedAt)
|
|
288
|
+
);
|
|
289
|
+
const startedAt = childStartTimes.length === 0 ? agentStart.startedAt : new Date(Math.min(agentStart.startedAt.getTime(), ...childStartTimes));
|
|
290
|
+
const endedAt = childEndTimes.length === 0 ? /* @__PURE__ */ new Date() : new Date(Math.max(...childEndTimes));
|
|
291
|
+
const agentObservation = traceObservation({
|
|
292
|
+
parentObservationId,
|
|
293
|
+
kind: "agent",
|
|
294
|
+
name: `${agentLabel(agentStart.agentId, agentStart.agentName)}.run`,
|
|
295
|
+
status: agentChildren.some((observation) => observation.status === "error") ? "error" : "success",
|
|
296
|
+
turn: this.parent.turn,
|
|
297
|
+
startedAt,
|
|
298
|
+
endedAt,
|
|
299
|
+
metadata: this.childMetadata(agentStart.agentId, agentStart.agentName, this.parent.turn)
|
|
300
|
+
});
|
|
301
|
+
observations.push(agentObservation);
|
|
302
|
+
agentObservationIds.set(agentStart.agentId, agentObservation.id);
|
|
303
|
+
}
|
|
304
|
+
for (const observation of this.completedObservations) {
|
|
305
|
+
const childAgentId = isRecord(observation.metadata) ? stringValue(observation.metadata.childAgentId) : void 0;
|
|
306
|
+
const childAgentObservationId = childAgentId === void 0 ? void 0 : agentObservationIds.get(childAgentId);
|
|
307
|
+
observations.push({
|
|
308
|
+
...observation,
|
|
309
|
+
parentObservationId: childAgentObservationId ?? parentObservationId
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return observations;
|
|
313
|
+
}
|
|
314
|
+
findToolStart(agentId, toolName, toolCallId) {
|
|
315
|
+
for (let index = this.toolStarts.length - 1; index >= 0; index -= 1) {
|
|
316
|
+
const start = this.toolStarts[index];
|
|
317
|
+
if (start === void 0 || start.completed || start.agentId !== agentId || start.toolName !== toolName) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
if (toolCallId === void 0 || start.toolCallId === toolCallId) {
|
|
321
|
+
return start;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return void 0;
|
|
325
|
+
}
|
|
326
|
+
childMetadata(agentId, agentName, childTurn) {
|
|
327
|
+
return compactJsonObject({
|
|
328
|
+
source: "agent_tool_event",
|
|
329
|
+
childAgentId: agentId,
|
|
330
|
+
childAgentName: agentName,
|
|
331
|
+
childTurn,
|
|
332
|
+
parentToolName: this.parent.toolName,
|
|
333
|
+
parentInternalCallId: this.parent.internalCallId,
|
|
334
|
+
parentToolCallId: this.parent.toolCallId
|
|
335
|
+
});
|
|
336
|
+
}
|
|
337
|
+
};
|
|
338
|
+
function generationKey(agentId, turn) {
|
|
339
|
+
return `${agentId}:${turn}`;
|
|
340
|
+
}
|
|
341
|
+
function agentLabel(agentId, agentName) {
|
|
342
|
+
return (agentName ?? agentId).replaceAll(/\s+/g, "_");
|
|
343
|
+
}
|
|
158
344
|
function traceObservation(props) {
|
|
159
|
-
const endedAt = /* @__PURE__ */ new Date();
|
|
345
|
+
const endedAt = props.endedAt ?? /* @__PURE__ */ new Date();
|
|
160
346
|
return {
|
|
161
347
|
id: globalThis.crypto.randomUUID(),
|
|
348
|
+
...props.parentObservationId === void 0 ? {} : { parentObservationId: props.parentObservationId },
|
|
162
349
|
kind: props.kind,
|
|
163
350
|
name: props.name,
|
|
164
351
|
status: props.status,
|
|
@@ -207,6 +394,12 @@ function parseOrString(value) {
|
|
|
207
394
|
return value;
|
|
208
395
|
}
|
|
209
396
|
}
|
|
397
|
+
function isRecord(value) {
|
|
398
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
399
|
+
}
|
|
400
|
+
function stringValue(value) {
|
|
401
|
+
return typeof value === "string" ? value : void 0;
|
|
402
|
+
}
|
|
210
403
|
function serializeError(error) {
|
|
211
404
|
if (error instanceof Error) {
|
|
212
405
|
return compactJsonObject({
|
|
@@ -544,15 +737,14 @@ var SqliteSessionStore = class {
|
|
|
544
737
|
};
|
|
545
738
|
}
|
|
546
739
|
getSession(id) {
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
return row === void 0 ? void 0 : toSession(row);
|
|
740
|
+
const row = this.getSessionRow(id);
|
|
741
|
+
return row === void 0 ? void 0 : toSession(row, this.listSessionRunRows(id));
|
|
742
|
+
}
|
|
743
|
+
load(context) {
|
|
744
|
+
const session = this.getSession(context.sessionId);
|
|
745
|
+
return Promise.resolve(session?.messages ?? []);
|
|
554
746
|
}
|
|
555
|
-
|
|
747
|
+
append(input) {
|
|
556
748
|
const db = this.database();
|
|
557
749
|
try {
|
|
558
750
|
db.exec("BEGIN IMMEDIATE");
|
|
@@ -560,39 +752,132 @@ var SqliteSessionStore = class {
|
|
|
560
752
|
`SELECT id, agent_id, title, metadata_json, messages_json, transcript_json, created_at, updated_at
|
|
561
753
|
FROM runner_sessions
|
|
562
754
|
WHERE id = $id`
|
|
563
|
-
).get({ $id: input.
|
|
755
|
+
).get({ $id: input.context.sessionId });
|
|
564
756
|
if (row === void 0) {
|
|
565
757
|
db.exec("ROLLBACK");
|
|
566
|
-
return
|
|
758
|
+
return Promise.resolve();
|
|
567
759
|
}
|
|
568
760
|
const current = toSession(row);
|
|
569
761
|
const messages = [...current.messages, ...input.messages];
|
|
570
|
-
const transcript = renumberTranscript([...current.transcript, ...input.transcript]);
|
|
571
|
-
const title = current.title ?? input.title;
|
|
572
762
|
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
763
|
+
db.prepare(
|
|
764
|
+
`UPDATE runner_sessions
|
|
765
|
+
SET messages_json = $messages,
|
|
766
|
+
updated_at = $updatedAt
|
|
767
|
+
WHERE id = $id`
|
|
768
|
+
).run({
|
|
769
|
+
$id: input.context.sessionId,
|
|
770
|
+
$messages: JSON.stringify(messages),
|
|
771
|
+
$updatedAt: updatedAt
|
|
772
|
+
});
|
|
773
|
+
db.exec("COMMIT");
|
|
774
|
+
return Promise.resolve();
|
|
775
|
+
} catch (error) {
|
|
776
|
+
if (db.isTransaction) {
|
|
777
|
+
db.exec("ROLLBACK");
|
|
778
|
+
}
|
|
779
|
+
throw error;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
clear(context) {
|
|
783
|
+
const db = this.database();
|
|
784
|
+
const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
785
|
+
try {
|
|
786
|
+
db.exec("BEGIN IMMEDIATE");
|
|
787
|
+
db.prepare(
|
|
788
|
+
`UPDATE runner_sessions
|
|
789
|
+
SET messages_json = '[]',
|
|
790
|
+
transcript_json = '[]',
|
|
791
|
+
updated_at = $updatedAt
|
|
792
|
+
WHERE id = $id`
|
|
793
|
+
).run({
|
|
794
|
+
$id: context.sessionId,
|
|
795
|
+
$updatedAt: updatedAt
|
|
796
|
+
});
|
|
797
|
+
db.prepare("DELETE FROM runner_session_runs WHERE session_id = $id").run({
|
|
798
|
+
$id: context.sessionId
|
|
799
|
+
});
|
|
800
|
+
db.exec("COMMIT");
|
|
801
|
+
return Promise.resolve();
|
|
802
|
+
} catch (error) {
|
|
803
|
+
if (db.isTransaction) {
|
|
804
|
+
db.exec("ROLLBACK");
|
|
805
|
+
}
|
|
806
|
+
throw error;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
async recordError(input) {
|
|
810
|
+
const runId = studioRunId(input.context) ?? input.runId;
|
|
811
|
+
const existing = this.getSessionRun(input.context.sessionId, runId);
|
|
812
|
+
const transcript = existing === void 0 || parseJsonArray(existing.transcript_json).length === 0 ? transcriptFromMessagesFallback(input.messages) : parseJsonArray(existing.transcript_json);
|
|
813
|
+
await this.saveSessionRunTranscript({
|
|
814
|
+
id: input.context.sessionId,
|
|
815
|
+
runId,
|
|
816
|
+
transcript,
|
|
817
|
+
status: "error",
|
|
818
|
+
error: serializeJsonError(input.error)
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
saveSessionRunTranscript(input) {
|
|
822
|
+
const db = this.database();
|
|
823
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
824
|
+
try {
|
|
825
|
+
db.exec("BEGIN IMMEDIATE");
|
|
826
|
+
const row = this.getSessionRow(input.id);
|
|
827
|
+
if (row === void 0) {
|
|
828
|
+
db.exec("ROLLBACK");
|
|
829
|
+
return void 0;
|
|
830
|
+
}
|
|
831
|
+
const current = toSession(row, this.listSessionRunRows(input.id));
|
|
832
|
+
const title = current.title ?? input.title;
|
|
833
|
+
db.prepare(
|
|
834
|
+
`INSERT INTO runner_session_runs (
|
|
835
|
+
run_id,
|
|
836
|
+
session_id,
|
|
837
|
+
status,
|
|
838
|
+
title,
|
|
839
|
+
transcript_json,
|
|
840
|
+
error_json,
|
|
841
|
+
created_at,
|
|
842
|
+
updated_at
|
|
843
|
+
) VALUES (
|
|
844
|
+
$runId,
|
|
845
|
+
$sessionId,
|
|
846
|
+
$status,
|
|
847
|
+
$title,
|
|
848
|
+
$transcript,
|
|
849
|
+
$error,
|
|
850
|
+
$now,
|
|
851
|
+
$now
|
|
852
|
+
)
|
|
853
|
+
ON CONFLICT(run_id) DO UPDATE SET
|
|
854
|
+
status = excluded.status,
|
|
855
|
+
title = COALESCE(runner_session_runs.title, excluded.title),
|
|
856
|
+
transcript_json = excluded.transcript_json,
|
|
857
|
+
error_json = excluded.error_json,
|
|
858
|
+
updated_at = excluded.updated_at`
|
|
859
|
+
).run({
|
|
860
|
+
$runId: input.runId,
|
|
861
|
+
$sessionId: input.id,
|
|
862
|
+
$status: input.status,
|
|
863
|
+
$title: input.title ?? null,
|
|
864
|
+
$transcript: JSON.stringify(renumberTranscript(input.transcript)),
|
|
865
|
+
$error: input.error === void 0 ? null : JSON.stringify(input.error),
|
|
866
|
+
$now: now
|
|
867
|
+
});
|
|
573
868
|
db.prepare(
|
|
574
869
|
`UPDATE runner_sessions
|
|
575
870
|
SET title = $title,
|
|
576
|
-
messages_json = $messages,
|
|
577
|
-
transcript_json = $transcript,
|
|
578
871
|
updated_at = $updatedAt
|
|
579
872
|
WHERE id = $id`
|
|
580
873
|
).run({
|
|
581
874
|
$id: input.id,
|
|
582
875
|
$title: title ?? null,
|
|
583
|
-
$
|
|
584
|
-
$transcript: JSON.stringify(transcript),
|
|
585
|
-
$updatedAt: updatedAt
|
|
876
|
+
$updatedAt: now
|
|
586
877
|
});
|
|
587
878
|
db.exec("COMMIT");
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
...title === void 0 ? {} : { title },
|
|
591
|
-
updatedAt,
|
|
592
|
-
messageCount: messages.length,
|
|
593
|
-
messages,
|
|
594
|
-
transcript
|
|
595
|
-
};
|
|
879
|
+
const updated = this.getSession(input.id);
|
|
880
|
+
return updated;
|
|
596
881
|
} catch (error) {
|
|
597
882
|
if (db.isTransaction) {
|
|
598
883
|
db.exec("ROLLBACK");
|
|
@@ -605,6 +890,7 @@ var SqliteSessionStore = class {
|
|
|
605
890
|
try {
|
|
606
891
|
db.exec("BEGIN IMMEDIATE");
|
|
607
892
|
db.prepare("DELETE FROM runner_traces WHERE session_id = $id").run({ $id: id });
|
|
893
|
+
db.prepare("DELETE FROM runner_session_runs WHERE session_id = $id").run({ $id: id });
|
|
608
894
|
const result = db.prepare("DELETE FROM runner_sessions WHERE id = $id").run({ $id: id });
|
|
609
895
|
db.exec("COMMIT");
|
|
610
896
|
return Number(result.changes) > 0;
|
|
@@ -765,6 +1051,19 @@ var SqliteSessionStore = class {
|
|
|
765
1051
|
) STRICT;
|
|
766
1052
|
CREATE INDEX IF NOT EXISTS runner_sessions_agent_updated_idx
|
|
767
1053
|
ON runner_sessions(agent_id, updated_at DESC);
|
|
1054
|
+
CREATE TABLE IF NOT EXISTS runner_session_runs (
|
|
1055
|
+
run_id TEXT PRIMARY KEY,
|
|
1056
|
+
session_id TEXT NOT NULL,
|
|
1057
|
+
status TEXT NOT NULL,
|
|
1058
|
+
title TEXT,
|
|
1059
|
+
transcript_json TEXT NOT NULL,
|
|
1060
|
+
error_json TEXT,
|
|
1061
|
+
created_at TEXT NOT NULL,
|
|
1062
|
+
updated_at TEXT NOT NULL,
|
|
1063
|
+
FOREIGN KEY(session_id) REFERENCES runner_sessions(id) ON DELETE CASCADE
|
|
1064
|
+
) STRICT;
|
|
1065
|
+
CREATE INDEX IF NOT EXISTS runner_session_runs_session_created_idx
|
|
1066
|
+
ON runner_session_runs(session_id, created_at ASC);
|
|
768
1067
|
CREATE TABLE IF NOT EXISTS runner_traces (
|
|
769
1068
|
id TEXT PRIMARY KEY,
|
|
770
1069
|
session_id TEXT NOT NULL,
|
|
@@ -787,13 +1086,39 @@ var SqliteSessionStore = class {
|
|
|
787
1086
|
this.db = db;
|
|
788
1087
|
return db;
|
|
789
1088
|
}
|
|
1089
|
+
getSessionRow(id) {
|
|
1090
|
+
return this.database().prepare(
|
|
1091
|
+
`SELECT id, agent_id, title, metadata_json, messages_json, transcript_json, created_at, updated_at
|
|
1092
|
+
FROM runner_sessions
|
|
1093
|
+
WHERE id = $id`
|
|
1094
|
+
).get({ $id: id });
|
|
1095
|
+
}
|
|
1096
|
+
getSessionRun(sessionId, runId) {
|
|
1097
|
+
return this.database().prepare(
|
|
1098
|
+
`SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
|
|
1099
|
+
FROM runner_session_runs
|
|
1100
|
+
WHERE session_id = $sessionId AND run_id = $runId`
|
|
1101
|
+
).get({ $sessionId: sessionId, $runId: runId });
|
|
1102
|
+
}
|
|
1103
|
+
listSessionRunRows(sessionId) {
|
|
1104
|
+
return this.database().prepare(
|
|
1105
|
+
`SELECT run_id, session_id, status, title, transcript_json, error_json, created_at, updated_at
|
|
1106
|
+
FROM runner_session_runs
|
|
1107
|
+
WHERE session_id = $sessionId
|
|
1108
|
+
ORDER BY created_at ASC`
|
|
1109
|
+
).all({ $sessionId: sessionId });
|
|
1110
|
+
}
|
|
790
1111
|
};
|
|
791
|
-
function toSession(row) {
|
|
1112
|
+
function toSession(row, runRows = []) {
|
|
792
1113
|
const summary = toSessionSummary(row);
|
|
1114
|
+
const legacyTranscript = parseJsonArray(row.transcript_json);
|
|
1115
|
+
const runTranscript = runRows.flatMap(
|
|
1116
|
+
(runRow) => parseJsonArray(runRow.transcript_json)
|
|
1117
|
+
);
|
|
793
1118
|
return {
|
|
794
1119
|
...summary,
|
|
795
1120
|
messages: parseJsonArray(row.messages_json),
|
|
796
|
-
transcript: renumberTranscript(
|
|
1121
|
+
transcript: renumberTranscript([...legacyTranscript, ...runTranscript])
|
|
797
1122
|
};
|
|
798
1123
|
}
|
|
799
1124
|
function toSessionSummary(row) {
|
|
@@ -852,6 +1177,96 @@ function parseJsonValue(value) {
|
|
|
852
1177
|
function renumberTranscript(entries) {
|
|
853
1178
|
return entries.map((entry, entryId) => ({ ...entry, entryId }));
|
|
854
1179
|
}
|
|
1180
|
+
function studioRunId(context) {
|
|
1181
|
+
const value = context.metadata?.studioRunId;
|
|
1182
|
+
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1183
|
+
}
|
|
1184
|
+
function serializeJsonError(error) {
|
|
1185
|
+
if (error instanceof Error) {
|
|
1186
|
+
return {
|
|
1187
|
+
name: error.name,
|
|
1188
|
+
message: error.message
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
if (error === null || typeof error === "string" || typeof error === "number" || typeof error === "boolean") {
|
|
1192
|
+
return error;
|
|
1193
|
+
}
|
|
1194
|
+
return String(error);
|
|
1195
|
+
}
|
|
1196
|
+
function transcriptFromMessagesFallback(messages) {
|
|
1197
|
+
const transcript = [];
|
|
1198
|
+
for (const message of messages) {
|
|
1199
|
+
if (message.role === "system") {
|
|
1200
|
+
continue;
|
|
1201
|
+
}
|
|
1202
|
+
if (message.role === "user") {
|
|
1203
|
+
for (const content of message.content) {
|
|
1204
|
+
if (content.type === "text") {
|
|
1205
|
+
transcript.push({
|
|
1206
|
+
entryId: transcript.length,
|
|
1207
|
+
kind: "message",
|
|
1208
|
+
role: "user",
|
|
1209
|
+
text: content.text
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
continue;
|
|
1214
|
+
}
|
|
1215
|
+
if (message.role === "tool") {
|
|
1216
|
+
for (const content of message.content) {
|
|
1217
|
+
transcript.push({
|
|
1218
|
+
entryId: transcript.length,
|
|
1219
|
+
kind: "tool",
|
|
1220
|
+
toolName: "tool_result",
|
|
1221
|
+
callId: content.callId ?? content.id,
|
|
1222
|
+
result: content.content.map((item) => "text" in item ? item.text : "[image]").join("\n")
|
|
1223
|
+
});
|
|
1224
|
+
}
|
|
1225
|
+
continue;
|
|
1226
|
+
}
|
|
1227
|
+
for (const content of message.content) {
|
|
1228
|
+
if (content.type === "text") {
|
|
1229
|
+
appendAssistantTranscriptText(transcript, content.text);
|
|
1230
|
+
} else if (content.type === "reasoning") {
|
|
1231
|
+
transcript.push({
|
|
1232
|
+
entryId: transcript.length,
|
|
1233
|
+
kind: "reasoning",
|
|
1234
|
+
...content.id === void 0 ? {} : { reasoningId: content.id },
|
|
1235
|
+
text: content.text
|
|
1236
|
+
});
|
|
1237
|
+
} else if (content.type === "tool_call") {
|
|
1238
|
+
transcript.push({
|
|
1239
|
+
entryId: transcript.length,
|
|
1240
|
+
kind: "tool",
|
|
1241
|
+
toolName: content.function.name,
|
|
1242
|
+
callId: content.callId ?? content.id,
|
|
1243
|
+
args: formatJson(content.function.arguments)
|
|
1244
|
+
});
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return transcript;
|
|
1249
|
+
}
|
|
1250
|
+
function appendAssistantTranscriptText(transcript, text) {
|
|
1251
|
+
const last = transcript.at(-1);
|
|
1252
|
+
if (last?.kind === "message" && last.role === "assistant") {
|
|
1253
|
+
last.text = `${last.text}${text}`;
|
|
1254
|
+
return;
|
|
1255
|
+
}
|
|
1256
|
+
transcript.push({
|
|
1257
|
+
entryId: transcript.length,
|
|
1258
|
+
kind: "message",
|
|
1259
|
+
role: "assistant",
|
|
1260
|
+
text
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1263
|
+
function formatJson(value) {
|
|
1264
|
+
try {
|
|
1265
|
+
return JSON.stringify(value, null, 2);
|
|
1266
|
+
} catch {
|
|
1267
|
+
return String(value);
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
855
1270
|
|
|
856
1271
|
// src/runtime/shared.ts
|
|
857
1272
|
function resolveStores(options) {
|
|
@@ -1369,7 +1784,7 @@ async function recentKnowledgeEvidence(traceStore, limit) {
|
|
|
1369
1784
|
}
|
|
1370
1785
|
function evidenceFromTrace(trace) {
|
|
1371
1786
|
return trace.observations.flatMap((observation) => {
|
|
1372
|
-
if (observation.kind !== "generation" || !
|
|
1787
|
+
if (observation.kind !== "generation" || !isRecord2(observation.input)) {
|
|
1373
1788
|
return [];
|
|
1374
1789
|
}
|
|
1375
1790
|
const documents = Array.isArray(observation.input.documents) ? observation.input.documents.flatMap((document) => evidenceDocument(document)) : [];
|
|
@@ -1422,7 +1837,7 @@ function messageText(value) {
|
|
|
1422
1837
|
if (typeof value === "string") {
|
|
1423
1838
|
return value.trim();
|
|
1424
1839
|
}
|
|
1425
|
-
if (!
|
|
1840
|
+
if (!isRecord2(value)) {
|
|
1426
1841
|
return "";
|
|
1427
1842
|
}
|
|
1428
1843
|
if (typeof value.text === "string") {
|
|
@@ -1440,7 +1855,7 @@ function contentText(value) {
|
|
|
1440
1855
|
if (typeof value === "string") {
|
|
1441
1856
|
return value.trim();
|
|
1442
1857
|
}
|
|
1443
|
-
if (!
|
|
1858
|
+
if (!isRecord2(value)) {
|
|
1444
1859
|
return "";
|
|
1445
1860
|
}
|
|
1446
1861
|
if (typeof value.text === "string") {
|
|
@@ -1449,12 +1864,12 @@ function contentText(value) {
|
|
|
1449
1864
|
return "";
|
|
1450
1865
|
}
|
|
1451
1866
|
function evidenceDocument(value) {
|
|
1452
|
-
if (!
|
|
1867
|
+
if (!isRecord2(value)) {
|
|
1453
1868
|
return [];
|
|
1454
1869
|
}
|
|
1455
1870
|
const id = typeof value.id === "string" ? value.id : void 0;
|
|
1456
1871
|
const text = typeof value.text === "string" ? value.text : void 0;
|
|
1457
|
-
const additionalProps =
|
|
1872
|
+
const additionalProps = isRecord2(value.additionalProps) ? jsonObjectFromRecord(value.additionalProps) : void 0;
|
|
1458
1873
|
if (id === void 0 && text === void 0 && additionalProps === void 0) {
|
|
1459
1874
|
return [];
|
|
1460
1875
|
}
|
|
@@ -1467,7 +1882,7 @@ function evidenceDocument(value) {
|
|
|
1467
1882
|
];
|
|
1468
1883
|
}
|
|
1469
1884
|
function evidenceToolName(value) {
|
|
1470
|
-
if (!
|
|
1885
|
+
if (!isRecord2(value) || typeof value.name !== "string") {
|
|
1471
1886
|
return [];
|
|
1472
1887
|
}
|
|
1473
1888
|
return [value.name];
|
|
@@ -1475,7 +1890,7 @@ function evidenceToolName(value) {
|
|
|
1475
1890
|
function jsonObjectFromRecord(value) {
|
|
1476
1891
|
return compactJsonObject2(value);
|
|
1477
1892
|
}
|
|
1478
|
-
function
|
|
1893
|
+
function isRecord2(value) {
|
|
1479
1894
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1480
1895
|
}
|
|
1481
1896
|
|
|
@@ -1823,22 +2238,42 @@ function traceForRun(trace, agentId, session) {
|
|
|
1823
2238
|
...trace?.sessionId !== void 0 ? { sessionId: trace.sessionId } : session === void 0 ? {} : { sessionId: session.id }
|
|
1824
2239
|
};
|
|
1825
2240
|
}
|
|
1826
|
-
async function*
|
|
2241
|
+
async function* persistStreamingSessionTranscript(props) {
|
|
1827
2242
|
const transcript = [messageToTranscriptEntry(props.message, 0)];
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
2243
|
+
const title = optionalTitle(props.message);
|
|
2244
|
+
await props.store.saveSessionRunTranscript({
|
|
2245
|
+
id: props.session.id,
|
|
2246
|
+
runId: props.runId,
|
|
2247
|
+
...title,
|
|
2248
|
+
transcript,
|
|
2249
|
+
status: "running"
|
|
2250
|
+
});
|
|
2251
|
+
try {
|
|
2252
|
+
for await (const event of props.stream) {
|
|
2253
|
+
acceptTranscriptStreamEvent(transcript, event);
|
|
2254
|
+
const nextSession = await props.store.saveSessionRunTranscript({
|
|
1832
2255
|
id: props.session.id,
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
transcript
|
|
2256
|
+
runId: props.runId,
|
|
2257
|
+
...title,
|
|
2258
|
+
transcript,
|
|
2259
|
+
status: event.type === "final" ? "success" : event.type === "error" ? "error" : "running",
|
|
2260
|
+
...event.type === "error" ? { error: serializeError2(event.error) } : {}
|
|
1836
2261
|
});
|
|
1837
2262
|
if (nextSession === void 0) {
|
|
1838
2263
|
throw new Error("Session not found");
|
|
1839
2264
|
}
|
|
2265
|
+
yield event;
|
|
1840
2266
|
}
|
|
1841
|
-
|
|
2267
|
+
} catch (error) {
|
|
2268
|
+
await props.store.saveSessionRunTranscript({
|
|
2269
|
+
id: props.session.id,
|
|
2270
|
+
runId: props.runId,
|
|
2271
|
+
...title,
|
|
2272
|
+
transcript,
|
|
2273
|
+
status: "error",
|
|
2274
|
+
error: serializeError2(error)
|
|
2275
|
+
});
|
|
2276
|
+
throw error;
|
|
1842
2277
|
}
|
|
1843
2278
|
}
|
|
1844
2279
|
function acceptTranscriptStreamEvent(transcript, event) {
|
|
@@ -1854,7 +2289,7 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
1854
2289
|
kind: "tool",
|
|
1855
2290
|
toolName: event.toolCall.function.name,
|
|
1856
2291
|
callId: event.toolCall.callId ?? event.toolCall.id,
|
|
1857
|
-
args:
|
|
2292
|
+
args: formatJson2(event.toolCall.function.arguments)
|
|
1858
2293
|
});
|
|
1859
2294
|
}
|
|
1860
2295
|
if (event.type === "tool_result") {
|
|
@@ -1873,6 +2308,22 @@ function acceptTranscriptStreamEvent(transcript, event) {
|
|
|
1873
2308
|
matched.args = matched.args ?? event.args;
|
|
1874
2309
|
matched.result = event.result;
|
|
1875
2310
|
}
|
|
2311
|
+
if (event.type === "agent_tool_event") {
|
|
2312
|
+
const matched = findTranscriptToolEntry(transcript, event.toolName, event.toolCallId);
|
|
2313
|
+
if (matched === void 0) {
|
|
2314
|
+
transcript.push({
|
|
2315
|
+
entryId: transcript.length,
|
|
2316
|
+
kind: "tool",
|
|
2317
|
+
toolName: event.toolName,
|
|
2318
|
+
...event.toolCallId === void 0 ? {} : { callId: event.toolCallId },
|
|
2319
|
+
childEvents: [childAgentTranscriptEvent(event)].filter(
|
|
2320
|
+
(childEvent) => childEvent !== void 0
|
|
2321
|
+
)
|
|
2322
|
+
});
|
|
2323
|
+
return;
|
|
2324
|
+
}
|
|
2325
|
+
appendChildAgentTranscriptEvent(matched, event);
|
|
2326
|
+
}
|
|
1876
2327
|
if (event.type === "tool_approval_request") {
|
|
1877
2328
|
const matched = findTranscriptToolEntry(
|
|
1878
2329
|
transcript,
|
|
@@ -1945,6 +2396,112 @@ function approvalCallId(approval) {
|
|
|
1945
2396
|
function questionCallId(question) {
|
|
1946
2397
|
return question.callId ?? question.toolCallId;
|
|
1947
2398
|
}
|
|
2399
|
+
function appendChildAgentTranscriptEvent(entry, event) {
|
|
2400
|
+
const childEvent = childAgentTranscriptEvent(event);
|
|
2401
|
+
if (childEvent === void 0) {
|
|
2402
|
+
return;
|
|
2403
|
+
}
|
|
2404
|
+
const childEvents = entry.childEvents ?? [];
|
|
2405
|
+
if (childEvent.kind === "message") {
|
|
2406
|
+
const last = childEvents.at(-1);
|
|
2407
|
+
if (last?.kind === "message" && last.agentId === childEvent.agentId) {
|
|
2408
|
+
last.text = `${last.text}${childEvent.text}`;
|
|
2409
|
+
} else {
|
|
2410
|
+
childEvents.push(childEvent);
|
|
2411
|
+
}
|
|
2412
|
+
} else if (childEvent.kind === "reasoning") {
|
|
2413
|
+
const last = childEvents.at(-1);
|
|
2414
|
+
if (last?.kind === "reasoning" && last.agentId === childEvent.agentId && (last.reasoningId ?? "") === (childEvent.reasoningId ?? "")) {
|
|
2415
|
+
last.text = `${last.text}${childEvent.text}`;
|
|
2416
|
+
} else {
|
|
2417
|
+
childEvents.push(childEvent);
|
|
2418
|
+
}
|
|
2419
|
+
} else {
|
|
2420
|
+
const matched = findChildAgentToolEvent(childEvents, childEvent);
|
|
2421
|
+
if (matched === void 0) {
|
|
2422
|
+
childEvents.push(childEvent);
|
|
2423
|
+
} else {
|
|
2424
|
+
if (matched.args === void 0 && childEvent.args !== void 0) {
|
|
2425
|
+
matched.args = childEvent.args;
|
|
2426
|
+
}
|
|
2427
|
+
if (childEvent.result !== void 0) {
|
|
2428
|
+
matched.result = childEvent.result;
|
|
2429
|
+
}
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
entry.childEvents = childEvents;
|
|
2433
|
+
}
|
|
2434
|
+
function childAgentTranscriptEvent(event) {
|
|
2435
|
+
const child = event.event;
|
|
2436
|
+
if (child.type === "text_delta") {
|
|
2437
|
+
return {
|
|
2438
|
+
kind: "message",
|
|
2439
|
+
agentId: event.agentId,
|
|
2440
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
2441
|
+
text: child.delta
|
|
2442
|
+
};
|
|
2443
|
+
}
|
|
2444
|
+
if (child.type === "reasoning_delta") {
|
|
2445
|
+
return {
|
|
2446
|
+
kind: "reasoning",
|
|
2447
|
+
agentId: event.agentId,
|
|
2448
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
2449
|
+
...child.id === void 0 ? {} : { reasoningId: child.id },
|
|
2450
|
+
text: child.delta
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
if (child.type === "tool_call") {
|
|
2454
|
+
return {
|
|
2455
|
+
kind: "tool",
|
|
2456
|
+
agentId: event.agentId,
|
|
2457
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
2458
|
+
toolName: child.toolCall.function.name,
|
|
2459
|
+
...child.toolCall.callId === void 0 && child.toolCall.id === void 0 ? {} : { callId: child.toolCall.callId ?? child.toolCall.id },
|
|
2460
|
+
args: formatJson2(child.toolCall.function.arguments)
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2463
|
+
if (child.type === "tool_result") {
|
|
2464
|
+
return {
|
|
2465
|
+
kind: "tool",
|
|
2466
|
+
agentId: event.agentId,
|
|
2467
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
2468
|
+
toolName: child.toolName,
|
|
2469
|
+
...child.toolCallId === void 0 ? {} : { callId: child.toolCallId },
|
|
2470
|
+
args: child.args,
|
|
2471
|
+
result: child.result
|
|
2472
|
+
};
|
|
2473
|
+
}
|
|
2474
|
+
if (child.type === "error") {
|
|
2475
|
+
return {
|
|
2476
|
+
kind: "message",
|
|
2477
|
+
agentId: event.agentId,
|
|
2478
|
+
...event.agentName === void 0 ? {} : { agentName: event.agentName },
|
|
2479
|
+
text: `Error: ${errorText(child.error)}`
|
|
2480
|
+
};
|
|
2481
|
+
}
|
|
2482
|
+
return void 0;
|
|
2483
|
+
}
|
|
2484
|
+
function errorText(error) {
|
|
2485
|
+
if (error instanceof Error) {
|
|
2486
|
+
return error.message;
|
|
2487
|
+
}
|
|
2488
|
+
if (typeof error === "string") {
|
|
2489
|
+
return error;
|
|
2490
|
+
}
|
|
2491
|
+
return JSON.stringify(serializeError2(error));
|
|
2492
|
+
}
|
|
2493
|
+
function findChildAgentToolEvent(childEvents, event) {
|
|
2494
|
+
for (let index = childEvents.length - 1; index >= 0; index -= 1) {
|
|
2495
|
+
const childEvent = childEvents[index];
|
|
2496
|
+
if (childEvent?.kind !== "tool" || childEvent.agentId !== event.agentId || childEvent.toolName !== event.toolName || childEvent.result !== void 0) {
|
|
2497
|
+
continue;
|
|
2498
|
+
}
|
|
2499
|
+
if (event.callId === void 0 || childEvent.callId === event.callId) {
|
|
2500
|
+
return childEvent;
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
return void 0;
|
|
2504
|
+
}
|
|
1948
2505
|
function transcriptFromMessages(messages) {
|
|
1949
2506
|
const transcript = [];
|
|
1950
2507
|
for (const message of messages) {
|
|
@@ -1987,7 +2544,7 @@ function transcriptFromMessages(messages) {
|
|
|
1987
2544
|
kind: "tool",
|
|
1988
2545
|
toolName: content.function.name,
|
|
1989
2546
|
callId: content.callId ?? content.id,
|
|
1990
|
-
args:
|
|
2547
|
+
args: formatJson2(content.function.arguments)
|
|
1991
2548
|
});
|
|
1992
2549
|
}
|
|
1993
2550
|
}
|
|
@@ -2073,7 +2630,7 @@ function extractMessageText(message) {
|
|
|
2073
2630
|
return [item.text];
|
|
2074
2631
|
}
|
|
2075
2632
|
if (item.type === "tool_call") {
|
|
2076
|
-
return [`${item.function.name}(${
|
|
2633
|
+
return [`${item.function.name}(${formatJson2(item.function.arguments)})`];
|
|
2077
2634
|
}
|
|
2078
2635
|
if (item.type === "tool_result") {
|
|
2079
2636
|
return item.content.map((result) => "text" in result ? result.text : "[image]");
|
|
@@ -2081,7 +2638,7 @@ function extractMessageText(message) {
|
|
|
2081
2638
|
return [];
|
|
2082
2639
|
}).join("\n");
|
|
2083
2640
|
}
|
|
2084
|
-
function
|
|
2641
|
+
function formatJson2(value) {
|
|
2085
2642
|
try {
|
|
2086
2643
|
return JSON.stringify(value, null, 2);
|
|
2087
2644
|
} catch {
|
|
@@ -2408,9 +2965,7 @@ function agentMetadata(agent) {
|
|
|
2408
2965
|
}
|
|
2409
2966
|
function createStudioApp(options) {
|
|
2410
2967
|
const stores = resolveStores(options);
|
|
2411
|
-
const agents = normalizeAgents(options.agents).map(
|
|
2412
|
-
(agent) => withStudioTraceObserver(agent, stores.traces)
|
|
2413
|
-
);
|
|
2968
|
+
const agents = normalizeAgents(options.agents).map((agent) => withStudioSessionMemory(agent, stores.sessions)).map((agent) => withStudioTraceObserver(agent, stores.traces));
|
|
2414
2969
|
const agentMap = new Map(agents.map((agent) => [agent.id, agent]));
|
|
2415
2970
|
const approvalRuntime = createApprovalRuntime();
|
|
2416
2971
|
const questionRuntime = createQuestionRuntime();
|
|
@@ -2469,12 +3024,14 @@ function createStudioApp(options) {
|
|
|
2469
3024
|
return errorResponse(c, 400, "bad_request", "Session belongs to another agent");
|
|
2470
3025
|
}
|
|
2471
3026
|
const runId = globalThis.crypto.randomUUID();
|
|
2472
|
-
const
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
}
|
|
3027
|
+
const memoryMetadata = {
|
|
3028
|
+
agentId,
|
|
3029
|
+
...body.metadata ?? {},
|
|
3030
|
+
studioRunId: runId
|
|
3031
|
+
};
|
|
3032
|
+
const request = session !== void 0 ? agent.agent.session(session.id, { metadata: memoryMetadata }).prompt(body.message) : agent.agent.prompt(
|
|
3033
|
+
body.history !== void 0 ? [...body.history, normalizePromptMessage(body.message)] : body.message
|
|
3034
|
+
);
|
|
2478
3035
|
if (body.maxTurns !== void 0) {
|
|
2479
3036
|
request.maxTurns(body.maxTurns);
|
|
2480
3037
|
}
|
|
@@ -2512,11 +3069,12 @@ function createStudioApp(options) {
|
|
|
2512
3069
|
request.requestHook(effectiveHook);
|
|
2513
3070
|
}
|
|
2514
3071
|
const runStream = mergeRunAndApprovalEvents(request.stream(), runtimeEvents);
|
|
2515
|
-
const stream = session === void 0 || stores.sessions === void 0 ? runStream :
|
|
3072
|
+
const stream = session === void 0 || stores.sessions === void 0 ? runStream : persistStreamingSessionTranscript({
|
|
2516
3073
|
stream: runStream,
|
|
2517
3074
|
store: stores.sessions,
|
|
2518
3075
|
session,
|
|
2519
|
-
message: body.message
|
|
3076
|
+
message: body.message,
|
|
3077
|
+
runId
|
|
2520
3078
|
});
|
|
2521
3079
|
return streamAgentRunEvents(c, stream);
|
|
2522
3080
|
}
|
|
@@ -2544,15 +3102,30 @@ function createStudioApp(options) {
|
|
|
2544
3102
|
}
|
|
2545
3103
|
const response = await request.send();
|
|
2546
3104
|
if (session !== void 0 && stores.sessions !== void 0) {
|
|
2547
|
-
await stores.sessions.
|
|
3105
|
+
await stores.sessions.saveSessionRunTranscript({
|
|
2548
3106
|
id: session.id,
|
|
3107
|
+
runId,
|
|
2549
3108
|
...optionalTitle(body.message),
|
|
2550
|
-
|
|
2551
|
-
|
|
3109
|
+
transcript: transcriptFromMessages(response.messages),
|
|
3110
|
+
status: "success"
|
|
2552
3111
|
});
|
|
2553
3112
|
}
|
|
2554
3113
|
return c.json(response);
|
|
2555
3114
|
} catch (error) {
|
|
3115
|
+
if (session !== void 0 && stores.sessions !== void 0) {
|
|
3116
|
+
const messages = await stores.sessions.load({
|
|
3117
|
+
sessionId: session.id,
|
|
3118
|
+
metadata: memoryMetadata
|
|
3119
|
+
});
|
|
3120
|
+
await stores.sessions.saveSessionRunTranscript({
|
|
3121
|
+
id: session.id,
|
|
3122
|
+
runId,
|
|
3123
|
+
...optionalTitle(body.message),
|
|
3124
|
+
transcript: transcriptFromMessages(messages.slice(session.messageCount)),
|
|
3125
|
+
status: "error",
|
|
3126
|
+
error: serializeError2(error)
|
|
3127
|
+
});
|
|
3128
|
+
}
|
|
2556
3129
|
return errorResponse(c, 500, "internal_error", "Agent run failed", serializeError2(error));
|
|
2557
3130
|
}
|
|
2558
3131
|
});
|
|
@@ -2584,36 +3157,60 @@ function createStudioApp(options) {
|
|
|
2584
3157
|
...stores.traces === void 0 ? {} : { traceStore: stores.traces }
|
|
2585
3158
|
};
|
|
2586
3159
|
}
|
|
3160
|
+
function normalizePromptMessage(message) {
|
|
3161
|
+
return typeof message === "string" ? Message.user(message) : message;
|
|
3162
|
+
}
|
|
3163
|
+
function withStudioSessionMemory(studioAgent, sessionStore) {
|
|
3164
|
+
if (sessionStore === void 0) {
|
|
3165
|
+
return studioAgent;
|
|
3166
|
+
}
|
|
3167
|
+
return {
|
|
3168
|
+
...studioAgent,
|
|
3169
|
+
agent: cloneAgent(studioAgent.agent, {
|
|
3170
|
+
memory: {
|
|
3171
|
+
store: sessionStore,
|
|
3172
|
+
options: resolveMemoryOptions({ savePolicy: "message" })
|
|
3173
|
+
}
|
|
3174
|
+
})
|
|
3175
|
+
};
|
|
3176
|
+
}
|
|
2587
3177
|
function withStudioTraceObserver(studioAgent, traceStore) {
|
|
2588
3178
|
if (traceStore === void 0 || hasStudioTraceObserver(studioAgent.agent)) {
|
|
2589
3179
|
return studioAgent;
|
|
2590
3180
|
}
|
|
2591
3181
|
return {
|
|
2592
3182
|
...studioAgent,
|
|
2593
|
-
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,
|
|
3183
|
+
agent: cloneAgent(studioAgent.agent, {
|
|
2608
3184
|
observers: [
|
|
2609
3185
|
...studioAgent.agent.observers,
|
|
2610
3186
|
{ observer: new StudioTraceObserver({ store: traceStore }) }
|
|
2611
|
-
]
|
|
2612
|
-
dynamicContexts: studioAgent.agent.dynamicContexts,
|
|
2613
|
-
dynamicTools: studioAgent.agent.dynamicTools
|
|
3187
|
+
]
|
|
2614
3188
|
})
|
|
2615
3189
|
};
|
|
2616
3190
|
}
|
|
3191
|
+
function cloneAgent(agent, overrides = {}) {
|
|
3192
|
+
return new Agent({
|
|
3193
|
+
id: agent.id,
|
|
3194
|
+
name: agent.name,
|
|
3195
|
+
description: agent.description,
|
|
3196
|
+
model: agent.model,
|
|
3197
|
+
instructions: agent.instructions,
|
|
3198
|
+
staticContext: agent.staticContext,
|
|
3199
|
+
temperature: agent.temperature,
|
|
3200
|
+
maxTokens: agent.maxTokens,
|
|
3201
|
+
additionalParams: agent.additionalParams,
|
|
3202
|
+
toolSet: agent.toolSet,
|
|
3203
|
+
toolChoice: agent.toolChoice,
|
|
3204
|
+
defaultMaxTurns: agent.defaultMaxTurns,
|
|
3205
|
+
hook: agent.hook,
|
|
3206
|
+
outputSchema: agent.outputSchema,
|
|
3207
|
+
observers: agent.observers,
|
|
3208
|
+
dynamicContexts: agent.dynamicContexts,
|
|
3209
|
+
dynamicTools: agent.dynamicTools,
|
|
3210
|
+
memory: agent.memory,
|
|
3211
|
+
...overrides
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
2617
3214
|
function hasStudioTraceObserver(agent) {
|
|
2618
3215
|
return agent.observers.some(
|
|
2619
3216
|
(registration) => registration.observer instanceof StudioTraceObserver
|