@agentica/core 0.32.2 → 0.32.3-dev.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/lib/index.mjs +320 -342
- package/lib/index.mjs.map +1 -1
- package/lib/orchestrate/call.js +87 -107
- package/lib/orchestrate/call.js.map +1 -1
- package/lib/orchestrate/describe.js +5 -50
- package/lib/orchestrate/describe.js.map +1 -1
- package/lib/orchestrate/initialize.js +5 -50
- package/lib/orchestrate/initialize.js.map +1 -1
- package/lib/orchestrate/select.js +107 -126
- package/lib/orchestrate/select.js.map +1 -1
- package/lib/utils/AssistantMessageEmptyError.d.ts +7 -0
- package/lib/utils/AssistantMessageEmptyError.js +17 -0
- package/lib/utils/AssistantMessageEmptyError.js.map +1 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.d.ts +8 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.js +86 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.js.map +1 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.spec.d.ts +1 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.spec.js +855 -0
- package/lib/utils/ChatGptCompletionStreamingUtil.spec.js.map +1 -0
- package/lib/utils/MPSC.js +8 -6
- package/lib/utils/MPSC.js.map +1 -1
- package/lib/utils/StreamUtil.d.ts +1 -1
- package/lib/utils/StreamUtil.js +2 -2
- package/lib/utils/StreamUtil.js.map +1 -1
- package/lib/utils/__retry.d.ts +1 -0
- package/lib/utils/__retry.js +30 -0
- package/lib/utils/__retry.js.map +1 -0
- package/lib/utils/__retry.spec.d.ts +1 -0
- package/lib/utils/__retry.spec.js +172 -0
- package/lib/utils/__retry.spec.js.map +1 -0
- package/package.json +1 -1
- package/src/orchestrate/call.ts +88 -114
- package/src/orchestrate/describe.ts +7 -65
- package/src/orchestrate/initialize.ts +4 -64
- package/src/orchestrate/select.ts +111 -138
- package/src/utils/AssistantMessageEmptyError.ts +13 -0
- package/src/utils/ChatGptCompletionMessageUtil.ts +1 -1
- package/src/utils/ChatGptCompletionStreamingUtil.spec.ts +908 -0
- package/src/utils/ChatGptCompletionStreamingUtil.ts +90 -0
- package/src/utils/MPSC.ts +8 -6
- package/src/utils/StreamUtil.ts +2 -2
- package/src/utils/__retry.spec.ts +198 -0
- package/src/utils/__retry.ts +18 -0
package/lib/index.mjs
CHANGED
|
@@ -808,93 +808,30 @@ function isAgenticaContext(ctx) {
|
|
|
808
808
|
return typeof ctx.initialize === "function";
|
|
809
809
|
}
|
|
810
810
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
811
|
+
function __get_retry(limit) {
|
|
812
|
+
const retryFn = async (fn, prevError, attempt = 0) => {
|
|
813
|
+
try {
|
|
814
|
+
return await fn(prevError);
|
|
815
|
+
} catch (error) {
|
|
816
|
+
if (attempt >= limit - 1) {
|
|
817
|
+
throw error;
|
|
818
|
+
}
|
|
819
|
+
return retryFn(fn, error, attempt + 1);
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
return retryFn;
|
|
816
823
|
}
|
|
817
824
|
|
|
818
|
-
class
|
|
825
|
+
class AssistantMessageEmptyError extends Error {
|
|
819
826
|
constructor() {
|
|
820
|
-
|
|
821
|
-
this.resolvers = [];
|
|
822
|
-
this.closeResolvers = [];
|
|
823
|
-
this.emptyResolvers = [];
|
|
824
|
-
this.closed = false;
|
|
825
|
-
}
|
|
826
|
-
enqueue(item) {
|
|
827
|
-
if (this.closed) {
|
|
828
|
-
console.error(new AsyncQueueClosedError("Cannot enqueue item: queue is closed."));
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
this.queue.push(item);
|
|
832
|
-
if (this.resolvers.length > 0) {
|
|
833
|
-
this.resolvers.shift()?.({
|
|
834
|
-
value: this.queue.shift(),
|
|
835
|
-
done: false
|
|
836
|
-
});
|
|
837
|
-
}
|
|
827
|
+
super();
|
|
838
828
|
}
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
|
-
if (this.isClosed()) {
|
|
848
|
-
return {
|
|
849
|
-
value: undefined,
|
|
850
|
-
done: true
|
|
851
|
-
};
|
|
852
|
-
}
|
|
853
|
-
return null;
|
|
854
|
-
})();
|
|
855
|
-
if (this.isEmpty() && this.emptyResolvers.length !== 0) {
|
|
856
|
-
this.emptyResolvers.forEach((resolve => resolve()));
|
|
857
|
-
this.emptyResolvers = [];
|
|
858
|
-
}
|
|
859
|
-
if (item !== null) {
|
|
860
|
-
return item;
|
|
861
|
-
}
|
|
862
|
-
return new Promise((resolve => this.resolvers.push(resolve)));
|
|
863
|
-
}
|
|
864
|
-
isEmpty() {
|
|
865
|
-
return this.queue.length === 0;
|
|
866
|
-
}
|
|
867
|
-
isClosed() {
|
|
868
|
-
return this.closed;
|
|
869
|
-
}
|
|
870
|
-
done() {
|
|
871
|
-
return this.isClosed() && this.isEmpty();
|
|
872
|
-
}
|
|
873
|
-
close() {
|
|
874
|
-
this.closed = true;
|
|
875
|
-
while (this.resolvers.length > 0) {
|
|
876
|
-
this.resolvers.shift()?.({
|
|
877
|
-
value: undefined,
|
|
878
|
-
done: true
|
|
879
|
-
});
|
|
880
|
-
}
|
|
881
|
-
this.closeResolvers.forEach((resolve => resolve()));
|
|
882
|
-
}
|
|
883
|
-
async waitUntilEmpty() {
|
|
884
|
-
if (this.isEmpty()) {
|
|
885
|
-
return Promise.resolve();
|
|
886
|
-
}
|
|
887
|
-
return new Promise((resolve => {
|
|
888
|
-
this.emptyResolvers.push(resolve);
|
|
889
|
-
}));
|
|
890
|
-
}
|
|
891
|
-
async waitClosed() {
|
|
892
|
-
if (this.isClosed()) {
|
|
893
|
-
return Promise.resolve();
|
|
894
|
-
}
|
|
895
|
-
return new Promise((resolve => {
|
|
896
|
-
this.closeResolvers.push(resolve);
|
|
897
|
-
}));
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
class AssistantMessageEmptyWithReasoningError extends AssistantMessageEmptyError {
|
|
832
|
+
constructor(reasoning) {
|
|
833
|
+
super();
|
|
834
|
+
this.reasoning = reasoning;
|
|
898
835
|
}
|
|
899
836
|
}
|
|
900
837
|
|
|
@@ -1100,17 +1037,109 @@ const ChatGptCompletionMessageUtil = {
|
|
|
1100
1037
|
mergeToolCalls
|
|
1101
1038
|
};
|
|
1102
1039
|
|
|
1040
|
+
class AsyncQueueClosedError extends Error {
|
|
1041
|
+
constructor(message) {
|
|
1042
|
+
super(message);
|
|
1043
|
+
this.name = "AsyncQueueClosedError";
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
|
|
1047
|
+
class AsyncQueue {
|
|
1048
|
+
constructor() {
|
|
1049
|
+
this.queue = [];
|
|
1050
|
+
this.resolvers = [];
|
|
1051
|
+
this.closeResolvers = [];
|
|
1052
|
+
this.emptyResolvers = [];
|
|
1053
|
+
this.closed = false;
|
|
1054
|
+
}
|
|
1055
|
+
enqueue(item) {
|
|
1056
|
+
if (this.closed) {
|
|
1057
|
+
console.error(new AsyncQueueClosedError("Cannot enqueue item: queue is closed."));
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
this.queue.push(item);
|
|
1061
|
+
if (this.resolvers.length > 0) {
|
|
1062
|
+
this.resolvers.shift()?.({
|
|
1063
|
+
value: this.queue.shift(),
|
|
1064
|
+
done: false
|
|
1065
|
+
});
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
async dequeue() {
|
|
1069
|
+
const item = (() => {
|
|
1070
|
+
if (!this.isEmpty()) {
|
|
1071
|
+
return {
|
|
1072
|
+
value: this.queue.shift(),
|
|
1073
|
+
done: false
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
if (this.isClosed()) {
|
|
1077
|
+
return {
|
|
1078
|
+
value: undefined,
|
|
1079
|
+
done: true
|
|
1080
|
+
};
|
|
1081
|
+
}
|
|
1082
|
+
return null;
|
|
1083
|
+
})();
|
|
1084
|
+
if (this.isEmpty() && this.emptyResolvers.length !== 0) {
|
|
1085
|
+
this.emptyResolvers.forEach((resolve => resolve()));
|
|
1086
|
+
this.emptyResolvers = [];
|
|
1087
|
+
}
|
|
1088
|
+
if (item !== null) {
|
|
1089
|
+
return item;
|
|
1090
|
+
}
|
|
1091
|
+
return new Promise((resolve => this.resolvers.push(resolve)));
|
|
1092
|
+
}
|
|
1093
|
+
isEmpty() {
|
|
1094
|
+
return this.queue.length === 0;
|
|
1095
|
+
}
|
|
1096
|
+
isClosed() {
|
|
1097
|
+
return this.closed;
|
|
1098
|
+
}
|
|
1099
|
+
done() {
|
|
1100
|
+
return this.isClosed() && this.isEmpty();
|
|
1101
|
+
}
|
|
1102
|
+
close() {
|
|
1103
|
+
this.closed = true;
|
|
1104
|
+
while (this.resolvers.length > 0) {
|
|
1105
|
+
this.resolvers.shift()?.({
|
|
1106
|
+
value: undefined,
|
|
1107
|
+
done: true
|
|
1108
|
+
});
|
|
1109
|
+
}
|
|
1110
|
+
this.closeResolvers.forEach((resolve => resolve()));
|
|
1111
|
+
}
|
|
1112
|
+
async waitUntilEmpty() {
|
|
1113
|
+
if (this.isEmpty()) {
|
|
1114
|
+
return Promise.resolve();
|
|
1115
|
+
}
|
|
1116
|
+
return new Promise((resolve => {
|
|
1117
|
+
this.emptyResolvers.push(resolve);
|
|
1118
|
+
}));
|
|
1119
|
+
}
|
|
1120
|
+
async waitClosed() {
|
|
1121
|
+
if (this.isClosed()) {
|
|
1122
|
+
return Promise.resolve();
|
|
1123
|
+
}
|
|
1124
|
+
return new Promise((resolve => {
|
|
1125
|
+
this.closeResolvers.push(resolve);
|
|
1126
|
+
}));
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1103
1130
|
class MPSC {
|
|
1104
1131
|
constructor() {
|
|
1105
1132
|
this.queue = new AsyncQueue;
|
|
1106
1133
|
this.consumer = new ReadableStream({
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1134
|
+
start: async controller => {
|
|
1135
|
+
while (true) {
|
|
1136
|
+
const {value, done} = await this.queue.dequeue();
|
|
1137
|
+
if (done === true) {
|
|
1138
|
+
controller.close();
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
controller.enqueue(value);
|
|
1112
1142
|
}
|
|
1113
|
-
controller.enqueue(value);
|
|
1114
1143
|
}
|
|
1115
1144
|
});
|
|
1116
1145
|
}
|
|
@@ -1158,10 +1187,10 @@ async function reduce(stream, reducer, initial) {
|
|
|
1158
1187
|
return acc;
|
|
1159
1188
|
}
|
|
1160
1189
|
|
|
1161
|
-
function from(value) {
|
|
1190
|
+
function from(...value) {
|
|
1162
1191
|
const stream = new ReadableStream({
|
|
1163
1192
|
start: controller => {
|
|
1164
|
-
controller.enqueue(
|
|
1193
|
+
value.forEach((v => controller.enqueue(v)));
|
|
1165
1194
|
controller.close();
|
|
1166
1195
|
}
|
|
1167
1196
|
});
|
|
@@ -1214,6 +1243,70 @@ var index$2 = Object.freeze({
|
|
|
1214
1243
|
toAsyncGenerator
|
|
1215
1244
|
});
|
|
1216
1245
|
|
|
1246
|
+
async function reduceStreamingWithDispatch(stream, eventProcessor) {
|
|
1247
|
+
const streamContext = new Map;
|
|
1248
|
+
const nullableCompletion = await StreamUtil.reduce(stream, (async (accPromise, chunk) => {
|
|
1249
|
+
const acc = await accPromise;
|
|
1250
|
+
const registerContext = choices => {
|
|
1251
|
+
for (const choice of choices) {
|
|
1252
|
+
if (choice.delta.content != null && choice.delta.content !== "") {
|
|
1253
|
+
if (streamContext.has(choice.index)) {
|
|
1254
|
+
const context = streamContext.get(choice.index);
|
|
1255
|
+
context.content += choice.delta.content;
|
|
1256
|
+
context.mpsc.produce(choice.delta.content);
|
|
1257
|
+
} else {
|
|
1258
|
+
const mpsc = new MPSC;
|
|
1259
|
+
streamContext.set(choice.index, {
|
|
1260
|
+
content: choice.delta.content,
|
|
1261
|
+
mpsc
|
|
1262
|
+
});
|
|
1263
|
+
mpsc.produce(choice.delta.content);
|
|
1264
|
+
eventProcessor({
|
|
1265
|
+
stream: streamDefaultReaderToAsyncGenerator(mpsc.consumer.getReader()),
|
|
1266
|
+
done: () => mpsc.done(),
|
|
1267
|
+
get: () => streamContext.get(choice.index)?.content ?? "",
|
|
1268
|
+
join: async () => {
|
|
1269
|
+
await mpsc.waitClosed();
|
|
1270
|
+
return streamContext.get(choice.index).content;
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
if (choice.finish_reason != null) {
|
|
1276
|
+
const context = streamContext.get(choice.index);
|
|
1277
|
+
if (context != null) {
|
|
1278
|
+
context.mpsc.close();
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
if (acc.object === "chat.completion.chunk") {
|
|
1284
|
+
registerContext([ acc, chunk ].flatMap((v => v.choices)));
|
|
1285
|
+
return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
|
|
1286
|
+
}
|
|
1287
|
+
registerContext(chunk.choices);
|
|
1288
|
+
return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
|
|
1289
|
+
}));
|
|
1290
|
+
if (nullableCompletion == null) {
|
|
1291
|
+
throw new Error("StreamUtil.reduce did not produce a ChatCompletion. Possible causes: the input stream was empty, invalid, or closed prematurely. " + "To debug: check that the stream is properly initialized and contains valid ChatCompletionChunk data. " + "You may also enable verbose logging upstream to inspect the stream contents. " + `Stream locked: ${stream.locked}.`);
|
|
1292
|
+
}
|
|
1293
|
+
if (nullableCompletion.object === "chat.completion.chunk") {
|
|
1294
|
+
const completion = ChatGptCompletionMessageUtil.merge([ nullableCompletion ]);
|
|
1295
|
+
completion.choices.forEach((choice => {
|
|
1296
|
+
if (choice.message.content != null && choice.message.content !== "") {
|
|
1297
|
+
eventProcessor({
|
|
1298
|
+
stream: toAsyncGenerator(choice.message.content),
|
|
1299
|
+
done: () => true,
|
|
1300
|
+
get: () => choice.message.content,
|
|
1301
|
+
join: async () => choice.message.content
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
}));
|
|
1305
|
+
return completion;
|
|
1306
|
+
}
|
|
1307
|
+
return nullableCompletion;
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1217
1310
|
function createOperationSelection(props) {
|
|
1218
1311
|
return {
|
|
1219
1312
|
operation: props.operation,
|
|
@@ -1242,87 +1335,66 @@ function cancelFunctionFromContext(ctx, reference) {
|
|
|
1242
1335
|
}
|
|
1243
1336
|
|
|
1244
1337
|
async function call(ctx, operations) {
|
|
1245
|
-
const
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
}, ...ctx.histories.map(decodeHistory).flat(), {
|
|
1250
|
-
role: "user",
|
|
1251
|
-
content: ctx.prompt.contents.map(decodeUserMessageContent)
|
|
1252
|
-
}, ...ctx.config?.systemPrompt?.execute === null ? [] : [ {
|
|
1253
|
-
role: "system",
|
|
1254
|
-
content: ctx.config?.systemPrompt?.execute?.(ctx.histories) ?? AgenticaSystemPrompt.EXECUTE
|
|
1255
|
-
} ] ],
|
|
1256
|
-
tools: operations.map((s => ({
|
|
1257
|
-
type: "function",
|
|
1258
|
-
function: {
|
|
1259
|
-
name: s.name,
|
|
1260
|
-
description: s.function.description,
|
|
1261
|
-
parameters: "separated" in s.function && s.function.separated !== undefined ? s.function.separated.llm ?? {
|
|
1262
|
-
type: "object",
|
|
1263
|
-
properties: {},
|
|
1264
|
-
required: [],
|
|
1265
|
-
additionalProperties: false,
|
|
1266
|
-
$defs: {}
|
|
1267
|
-
} : s.function.parameters
|
|
1268
|
-
}
|
|
1269
|
-
}))),
|
|
1270
|
-
tool_choice: "auto"
|
|
1271
|
-
});
|
|
1272
|
-
const selectContext = [];
|
|
1273
|
-
const nullableCompletion = await StreamUtil.reduce(stream, (async (accPromise, chunk) => {
|
|
1274
|
-
const acc = await accPromise;
|
|
1275
|
-
const registerContext = choices => {
|
|
1276
|
-
for (const choice of choices) {
|
|
1277
|
-
if (choice.finish_reason != null) {
|
|
1278
|
-
selectContext[choice.index]?.mpsc.close();
|
|
1279
|
-
continue;
|
|
1280
|
-
}
|
|
1281
|
-
if (choice.delta.content == null || choice.delta.content === "") {
|
|
1282
|
-
continue;
|
|
1283
|
-
}
|
|
1284
|
-
if (selectContext[choice.index] != null) {
|
|
1285
|
-
selectContext[choice.index].content += choice.delta.content;
|
|
1286
|
-
selectContext[choice.index].mpsc.produce(choice.delta.content);
|
|
1287
|
-
continue;
|
|
1288
|
-
}
|
|
1289
|
-
const mpsc = new MPSC;
|
|
1290
|
-
selectContext[choice.index] = {
|
|
1291
|
-
content: choice.delta.content,
|
|
1292
|
-
mpsc
|
|
1293
|
-
};
|
|
1294
|
-
mpsc.produce(choice.delta.content);
|
|
1295
|
-
const event = createAssistantMessageEvent({
|
|
1296
|
-
stream: streamDefaultReaderToAsyncGenerator(mpsc.consumer.getReader()),
|
|
1297
|
-
done: () => mpsc.done(),
|
|
1298
|
-
get: () => selectContext[choice.index]?.content ?? "",
|
|
1299
|
-
join: async () => {
|
|
1300
|
-
await mpsc.waitClosed();
|
|
1301
|
-
return selectContext[choice.index].content;
|
|
1302
|
-
}
|
|
1303
|
-
});
|
|
1304
|
-
ctx.dispatch(event);
|
|
1305
|
-
}
|
|
1306
|
-
};
|
|
1307
|
-
if (acc.object === "chat.completion.chunk") {
|
|
1308
|
-
registerContext([ acc, chunk ].flatMap((v => v.choices)));
|
|
1309
|
-
return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
|
|
1338
|
+
const _retryFn = __get_retry(ctx.config?.retry ?? AgenticaConstant.RETRY);
|
|
1339
|
+
const retryFn = async fn => _retryFn(fn).catch((e => {
|
|
1340
|
+
if (e instanceof AssistantMessageEmptyError) {
|
|
1341
|
+
return Symbol("emptyAssistantMessage");
|
|
1310
1342
|
}
|
|
1311
|
-
|
|
1312
|
-
return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
|
|
1343
|
+
throw e;
|
|
1313
1344
|
}));
|
|
1314
|
-
const completion =
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1345
|
+
const completion = await retryFn((async prevError => {
|
|
1346
|
+
const stream = await ctx.request("call", {
|
|
1347
|
+
messages: [ {
|
|
1348
|
+
role: "system",
|
|
1349
|
+
content: AgenticaDefaultPrompt.write(ctx.config)
|
|
1350
|
+
}, ...ctx.histories.map(decodeHistory).flat(), {
|
|
1351
|
+
role: "user",
|
|
1352
|
+
content: ctx.prompt.contents.map(decodeUserMessageContent)
|
|
1353
|
+
}, ...prevError instanceof AssistantMessageEmptyWithReasoningError ? [ {
|
|
1354
|
+
role: "assistant",
|
|
1355
|
+
content: prevError.reasoning
|
|
1356
|
+
} ] : [], ...ctx.config?.systemPrompt?.execute === null ? [] : [ {
|
|
1357
|
+
role: "system",
|
|
1358
|
+
content: ctx.config?.systemPrompt?.execute?.(ctx.histories) ?? AgenticaSystemPrompt.EXECUTE
|
|
1359
|
+
} ] ],
|
|
1360
|
+
tools: operations.map((s => ({
|
|
1361
|
+
type: "function",
|
|
1362
|
+
function: {
|
|
1363
|
+
name: s.name,
|
|
1364
|
+
description: s.function.description,
|
|
1365
|
+
parameters: "separated" in s.function && s.function.separated !== undefined ? s.function.separated.llm ?? {
|
|
1366
|
+
type: "object",
|
|
1367
|
+
properties: {},
|
|
1368
|
+
required: [],
|
|
1369
|
+
additionalProperties: false,
|
|
1370
|
+
$defs: {}
|
|
1371
|
+
} : s.function.parameters
|
|
1372
|
+
}
|
|
1373
|
+
}))),
|
|
1374
|
+
tool_choice: "auto"
|
|
1375
|
+
});
|
|
1376
|
+
const completion = await reduceStreamingWithDispatch(stream, (props => {
|
|
1377
|
+
const event = createAssistantMessageEvent(props);
|
|
1324
1378
|
ctx.dispatch(event);
|
|
1325
1379
|
}));
|
|
1380
|
+
const allAssistantMessagesEmpty = completion.choices.every((v => v.message.tool_calls == null && v.message.content === ""));
|
|
1381
|
+
if (allAssistantMessagesEmpty) {
|
|
1382
|
+
const firstChoice = completion.choices.at(0);
|
|
1383
|
+
if (firstChoice?.message?.reasoning != null) {
|
|
1384
|
+
throw new AssistantMessageEmptyWithReasoningError(firstChoice?.message?.reasoning ?? "");
|
|
1385
|
+
}
|
|
1386
|
+
throw new AssistantMessageEmptyError;
|
|
1387
|
+
}
|
|
1388
|
+
return completion;
|
|
1389
|
+
}));
|
|
1390
|
+
if (typeof completion === "symbol") {
|
|
1391
|
+
const event = createAssistantMessageEvent({
|
|
1392
|
+
stream: toAsyncGenerator(""),
|
|
1393
|
+
done: () => true,
|
|
1394
|
+
get: () => "",
|
|
1395
|
+
join: async () => ""
|
|
1396
|
+
});
|
|
1397
|
+
ctx.dispatch(event);
|
|
1326
1398
|
return [];
|
|
1327
1399
|
}
|
|
1328
1400
|
const executes = [];
|
|
@@ -1872,48 +1944,12 @@ async function describe(ctx, histories) {
|
|
|
1872
1944
|
content: ctx.config?.systemPrompt?.describe?.(histories) ?? AgenticaSystemPrompt.DESCRIBE
|
|
1873
1945
|
} ]
|
|
1874
1946
|
});
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
describeContext[choice.index].mpsc.close();
|
|
1882
|
-
continue;
|
|
1883
|
-
}
|
|
1884
|
-
if (choice.delta.content == null) {
|
|
1885
|
-
continue;
|
|
1886
|
-
}
|
|
1887
|
-
if (describeContext[choice.index] != null) {
|
|
1888
|
-
describeContext[choice.index].content += choice.delta.content;
|
|
1889
|
-
describeContext[choice.index].mpsc.produce(choice.delta.content);
|
|
1890
|
-
continue;
|
|
1891
|
-
}
|
|
1892
|
-
const mpsc = new MPSC;
|
|
1893
|
-
describeContext[choice.index] = {
|
|
1894
|
-
content: choice.delta.content,
|
|
1895
|
-
mpsc
|
|
1896
|
-
};
|
|
1897
|
-
mpsc.produce(choice.delta.content);
|
|
1898
|
-
const event = createDescribeEvent({
|
|
1899
|
-
executes: histories,
|
|
1900
|
-
stream: streamDefaultReaderToAsyncGenerator(mpsc.consumer.getReader()),
|
|
1901
|
-
done: () => mpsc.done(),
|
|
1902
|
-
get: () => describeContext[choice.index]?.content ?? "",
|
|
1903
|
-
join: async () => {
|
|
1904
|
-
await mpsc.waitClosed();
|
|
1905
|
-
return describeContext[choice.index].content;
|
|
1906
|
-
}
|
|
1907
|
-
});
|
|
1908
|
-
ctx.dispatch(event);
|
|
1909
|
-
}
|
|
1910
|
-
};
|
|
1911
|
-
if (acc.object === "chat.completion.chunk") {
|
|
1912
|
-
registerContext([ acc, chunk ].flatMap((v => v.choices)));
|
|
1913
|
-
return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
|
|
1914
|
-
}
|
|
1915
|
-
registerContext(chunk.choices);
|
|
1916
|
-
return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
|
|
1947
|
+
await reduceStreamingWithDispatch(completionStream, (props => {
|
|
1948
|
+
const event = createDescribeEvent({
|
|
1949
|
+
executes: histories,
|
|
1950
|
+
...props
|
|
1951
|
+
});
|
|
1952
|
+
ctx.dispatch(event);
|
|
1917
1953
|
}));
|
|
1918
1954
|
}
|
|
1919
1955
|
|
|
@@ -2578,47 +2614,9 @@ async function initialize(ctx) {
|
|
|
2578
2614
|
} ],
|
|
2579
2615
|
tool_choice: "auto"
|
|
2580
2616
|
});
|
|
2581
|
-
const
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
const registerContext = choices => {
|
|
2585
|
-
for (const choice of choices) {
|
|
2586
|
-
if (choice.finish_reason != null) {
|
|
2587
|
-
textContext[choice.index]?.mpsc.close();
|
|
2588
|
-
continue;
|
|
2589
|
-
}
|
|
2590
|
-
if (choice.delta.content == null || choice.delta.content.length === 0) {
|
|
2591
|
-
continue;
|
|
2592
|
-
}
|
|
2593
|
-
if (textContext[choice.index] != null) {
|
|
2594
|
-
textContext[choice.index].content += choice.delta.content;
|
|
2595
|
-
textContext[choice.index].mpsc.produce(choice.delta.content);
|
|
2596
|
-
continue;
|
|
2597
|
-
}
|
|
2598
|
-
const mpsc = new MPSC;
|
|
2599
|
-
textContext[choice.index] = {
|
|
2600
|
-
content: choice.delta.content,
|
|
2601
|
-
mpsc
|
|
2602
|
-
};
|
|
2603
|
-
mpsc.produce(choice.delta.content);
|
|
2604
|
-
const event = createAssistantMessageEvent({
|
|
2605
|
-
stream: streamDefaultReaderToAsyncGenerator(mpsc.consumer.getReader()),
|
|
2606
|
-
done: () => mpsc.done(),
|
|
2607
|
-
get: () => textContext[choice.index].content,
|
|
2608
|
-
join: async () => {
|
|
2609
|
-
await mpsc.waitClosed();
|
|
2610
|
-
return textContext[choice.index].content;
|
|
2611
|
-
}
|
|
2612
|
-
});
|
|
2613
|
-
ctx.dispatch(event);
|
|
2614
|
-
}
|
|
2615
|
-
};
|
|
2616
|
-
if (acc.object === "chat.completion.chunk") {
|
|
2617
|
-
registerContext([ acc, chunk ].flatMap((v => v.choices)));
|
|
2618
|
-
return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
|
|
2619
|
-
}
|
|
2620
|
-
registerContext(chunk.choices);
|
|
2621
|
-
return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
|
|
2617
|
+
const completion = await reduceStreamingWithDispatch(completionStream, (props => {
|
|
2618
|
+
const event = createAssistantMessageEvent(props);
|
|
2619
|
+
ctx.dispatch(event);
|
|
2622
2620
|
}));
|
|
2623
2621
|
if (completion === null) {
|
|
2624
2622
|
throw new Error("No completion received");
|
|
@@ -2766,103 +2764,83 @@ async function select(ctx) {
|
|
|
2766
2764
|
}
|
|
2767
2765
|
|
|
2768
2766
|
async function step(ctx, operations, retry, failures) {
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
}
|
|
2774
|
-
|
|
2775
|
-
|
|
2767
|
+
const _retryFn = __get_retry(ctx.config?.retry ?? AgenticaConstant.RETRY);
|
|
2768
|
+
const retryFn = async fn => _retryFn(fn).catch((e => {
|
|
2769
|
+
if (e instanceof AssistantMessageEmptyError) {
|
|
2770
|
+
return Symbol("emptyAssistantMessage");
|
|
2771
|
+
}
|
|
2772
|
+
throw e;
|
|
2773
|
+
}));
|
|
2774
|
+
const completion = await retryFn((async prevError => {
|
|
2775
|
+
const stream = await ctx.request("select", {
|
|
2776
|
+
messages: [ {
|
|
2777
|
+
role: "system",
|
|
2778
|
+
content: AgenticaDefaultPrompt.write(ctx.config)
|
|
2779
|
+
}, {
|
|
2780
|
+
role: "assistant",
|
|
2781
|
+
tool_calls: [ {
|
|
2782
|
+
type: "function",
|
|
2783
|
+
id: "getApiFunctions",
|
|
2784
|
+
function: {
|
|
2785
|
+
name: "getApiFunctions",
|
|
2786
|
+
arguments: JSON.stringify({})
|
|
2787
|
+
}
|
|
2788
|
+
} ]
|
|
2789
|
+
}, {
|
|
2790
|
+
role: "tool",
|
|
2791
|
+
tool_call_id: "getApiFunctions",
|
|
2792
|
+
content: JSON.stringify(operations.map((op => ({
|
|
2793
|
+
name: op.name,
|
|
2794
|
+
description: op.function.description,
|
|
2795
|
+
...op.protocol === "http" ? {
|
|
2796
|
+
method: op.function.method,
|
|
2797
|
+
path: op.function.path,
|
|
2798
|
+
tags: op.function.tags
|
|
2799
|
+
} : {}
|
|
2800
|
+
}))))
|
|
2801
|
+
}, ...ctx.histories.map(decodeHistory).flat(), {
|
|
2802
|
+
role: "user",
|
|
2803
|
+
content: ctx.prompt.contents.map(decodeUserMessageContent)
|
|
2804
|
+
}, ...prevError instanceof AssistantMessageEmptyWithReasoningError ? [ {
|
|
2805
|
+
role: "assistant",
|
|
2806
|
+
content: prevError.reasoning
|
|
2807
|
+
} ] : [], {
|
|
2808
|
+
role: "system",
|
|
2809
|
+
content: ctx.config?.systemPrompt?.select?.(ctx.histories) ?? AgenticaSystemPrompt.SELECT
|
|
2810
|
+
}, ...emendMessages(failures ?? []) ],
|
|
2811
|
+
tools: [ {
|
|
2776
2812
|
type: "function",
|
|
2777
|
-
id: "getApiFunctions",
|
|
2778
2813
|
function: {
|
|
2779
|
-
name:
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
} ]
|
|
2783
|
-
}, {
|
|
2784
|
-
role: "tool",
|
|
2785
|
-
tool_call_id: "getApiFunctions",
|
|
2786
|
-
content: JSON.stringify(operations.map((op => ({
|
|
2787
|
-
name: op.name,
|
|
2788
|
-
description: op.function.description,
|
|
2789
|
-
...op.protocol === "http" ? {
|
|
2790
|
-
method: op.function.method,
|
|
2791
|
-
path: op.function.path,
|
|
2792
|
-
tags: op.function.tags
|
|
2793
|
-
} : {}
|
|
2794
|
-
}))))
|
|
2795
|
-
}, ...ctx.histories.map(decodeHistory).flat(), {
|
|
2796
|
-
role: "user",
|
|
2797
|
-
content: ctx.prompt.contents.map(decodeUserMessageContent)
|
|
2798
|
-
}, {
|
|
2799
|
-
role: "system",
|
|
2800
|
-
content: ctx.config?.systemPrompt?.select?.(ctx.histories) ?? AgenticaSystemPrompt.SELECT
|
|
2801
|
-
}, ...emendMessages(failures ?? []) ],
|
|
2802
|
-
tools: [ {
|
|
2803
|
-
type: "function",
|
|
2804
|
-
function: {
|
|
2805
|
-
name: CONTAINER.functions[0].name,
|
|
2806
|
-
description: CONTAINER.functions[0].description,
|
|
2807
|
-
parameters: CONTAINER.functions[0].parameters
|
|
2808
|
-
}
|
|
2809
|
-
} ],
|
|
2810
|
-
tool_choice: retry === 0 ? "auto" : "required"
|
|
2811
|
-
});
|
|
2812
|
-
const selectContext = [];
|
|
2813
|
-
const nullableCompletion = await StreamUtil.reduce(completionStream, (async (accPromise, chunk) => {
|
|
2814
|
-
const acc = await accPromise;
|
|
2815
|
-
const registerContext = choices => {
|
|
2816
|
-
for (const choice of choices) {
|
|
2817
|
-
if (choice.finish_reason != null) {
|
|
2818
|
-
selectContext[choice.index]?.mpsc.close();
|
|
2819
|
-
continue;
|
|
2814
|
+
name: CONTAINER.functions[0].name,
|
|
2815
|
+
description: CONTAINER.functions[0].description,
|
|
2816
|
+
parameters: CONTAINER.functions[0].parameters
|
|
2820
2817
|
}
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
};
|
|
2834
|
-
mpsc.produce(choice.delta.content);
|
|
2835
|
-
const event = createAssistantMessageEvent({
|
|
2836
|
-
stream: streamDefaultReaderToAsyncGenerator(mpsc.consumer.getReader()),
|
|
2837
|
-
done: () => mpsc.done(),
|
|
2838
|
-
get: () => selectContext[choice.index]?.content ?? "",
|
|
2839
|
-
join: async () => {
|
|
2840
|
-
await mpsc.waitClosed();
|
|
2841
|
-
return selectContext[choice.index].content;
|
|
2842
|
-
}
|
|
2843
|
-
});
|
|
2844
|
-
ctx.dispatch(event);
|
|
2818
|
+
} ],
|
|
2819
|
+
tool_choice: retry === 0 ? "auto" : "required"
|
|
2820
|
+
});
|
|
2821
|
+
const completion = await reduceStreamingWithDispatch(stream, (props => {
|
|
2822
|
+
const event = createAssistantMessageEvent(props);
|
|
2823
|
+
ctx.dispatch(event);
|
|
2824
|
+
}));
|
|
2825
|
+
const allAssistantMessagesEmpty = completion.choices.every((v => v.message.tool_calls == null && v.message.content === ""));
|
|
2826
|
+
if (allAssistantMessagesEmpty) {
|
|
2827
|
+
const firstChoice = completion.choices.at(0);
|
|
2828
|
+
if (firstChoice?.message?.reasoning != null) {
|
|
2829
|
+
throw new AssistantMessageEmptyWithReasoningError(firstChoice?.message?.reasoning ?? "");
|
|
2845
2830
|
}
|
|
2846
|
-
|
|
2847
|
-
if (acc.object === "chat.completion.chunk") {
|
|
2848
|
-
registerContext([ acc, chunk ].flatMap((v => v.choices)));
|
|
2849
|
-
return ChatGptCompletionMessageUtil.merge([ acc, chunk ]);
|
|
2831
|
+
throw new AssistantMessageEmptyError;
|
|
2850
2832
|
}
|
|
2851
|
-
|
|
2852
|
-
return ChatGptCompletionMessageUtil.accumulate(acc, chunk);
|
|
2833
|
+
return completion;
|
|
2853
2834
|
}));
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
});
|
|
2864
|
-
ctx.dispatch(event);
|
|
2865
|
-
}));
|
|
2835
|
+
if (typeof completion === "symbol") {
|
|
2836
|
+
const event = createAssistantMessageEvent({
|
|
2837
|
+
stream: toAsyncGenerator(""),
|
|
2838
|
+
done: () => true,
|
|
2839
|
+
get: () => "",
|
|
2840
|
+
join: async () => ""
|
|
2841
|
+
});
|
|
2842
|
+
ctx.dispatch(event);
|
|
2843
|
+
return;
|
|
2866
2844
|
}
|
|
2867
2845
|
if (retry++ < (ctx.config?.retry ?? AgenticaConstant.RETRY)) {
|
|
2868
2846
|
const failures = [];
|