@cuylabs/agent-foundry-hosting 4.8.0 → 4.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -3
- package/dist/chunk-BK7IBLJL.js +61 -0
- package/dist/chunk-M7O23JGF.js +493 -0
- package/dist/{chunk-D5U6N54E.js → chunk-SJJFHS66.js} +4 -59
- package/dist/index.d.ts +2 -0
- package/dist/index.js +7 -2
- package/dist/invocations/index.js +4 -2
- package/dist/responses/index.d.ts +59 -0
- package/dist/responses/index.js +21 -0
- package/package.json +16 -9
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ lower-level Agent Server protocol packages:
|
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
10
|
@cuylabs/agent-foundry-agentserver-invocations -> azure-ai-agentserver-invocations
|
|
11
|
+
@cuylabs/agent-foundry-agentserver-responses -> azure-ai-agentserver-responses
|
|
11
12
|
@cuylabs/agent-foundry-hosting -> agent-framework-foundry-hosting
|
|
12
13
|
```
|
|
13
14
|
|
|
@@ -31,6 +32,23 @@ await runInvocationsServer({
|
|
|
31
32
|
|
|
32
33
|
## Responses
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
```ts
|
|
36
|
+
import { runResponsesServer } from "@cuylabs/agent-foundry-agentserver-responses";
|
|
37
|
+
import { createResponsesHandlerForAgent } from "@cuylabs/agent-foundry-hosting/responses";
|
|
38
|
+
import {
|
|
39
|
+
createAgentServerAdapter,
|
|
40
|
+
InProcessAgentServer,
|
|
41
|
+
} from "@cuylabs/agent-server";
|
|
42
|
+
|
|
43
|
+
const server = new InProcessAgentServer(createAgentServerAdapter(myAgent));
|
|
44
|
+
|
|
45
|
+
await runResponsesServer({
|
|
46
|
+
handler: createResponsesHandlerForAgent(server),
|
|
47
|
+
port: 8088,
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The Responses bridge starts an `agent-server` turn for each create-response
|
|
52
|
+
request, maps `agent-core` text/tool/error/completion events into Responses
|
|
53
|
+
stream events, and leaves HTTP, SSE framing, IDs, storage, and platform headers
|
|
54
|
+
to `@cuylabs/agent-foundry-agentserver-responses`.
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/invocations/async-queue.ts
|
|
2
|
+
var AsyncQueue = class {
|
|
3
|
+
values = [];
|
|
4
|
+
waiters = [];
|
|
5
|
+
closed = false;
|
|
6
|
+
push(value, coalesce) {
|
|
7
|
+
if (this.closed) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
const waiter = this.waiters.shift();
|
|
11
|
+
if (waiter) {
|
|
12
|
+
waiter({ value, done: false });
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (coalesce && this.values.length > 0) {
|
|
16
|
+
const lastIndex = this.values.length - 1;
|
|
17
|
+
const merged = coalesce(this.values[lastIndex], value);
|
|
18
|
+
if (merged !== void 0) {
|
|
19
|
+
this.values[lastIndex] = merged;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
this.values.push(value);
|
|
24
|
+
}
|
|
25
|
+
close() {
|
|
26
|
+
if (this.closed) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.closed = true;
|
|
30
|
+
for (const waiter of this.waiters.splice(0)) {
|
|
31
|
+
waiter({ value: void 0, done: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
reset() {
|
|
35
|
+
this.values = [];
|
|
36
|
+
this.closed = false;
|
|
37
|
+
}
|
|
38
|
+
async *[Symbol.asyncIterator]() {
|
|
39
|
+
while (true) {
|
|
40
|
+
if (this.values.length > 0) {
|
|
41
|
+
const value = this.values.shift();
|
|
42
|
+
yield value;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (this.closed) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const result = await new Promise((resolve) => {
|
|
49
|
+
this.waiters.push(resolve);
|
|
50
|
+
});
|
|
51
|
+
if (result.done) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
yield result.value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export {
|
|
60
|
+
AsyncQueue
|
|
61
|
+
};
|
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AsyncQueue
|
|
3
|
+
} from "./chunk-BK7IBLJL.js";
|
|
4
|
+
|
|
5
|
+
// src/responses/index.ts
|
|
6
|
+
import {
|
|
7
|
+
ResponsesHandler,
|
|
8
|
+
TextResponse
|
|
9
|
+
} from "@cuylabs/agent-foundry-agentserver-responses";
|
|
10
|
+
|
|
11
|
+
// src/responses/events.ts
|
|
12
|
+
import {
|
|
13
|
+
createResponseObject,
|
|
14
|
+
newId,
|
|
15
|
+
newOutputMessageItemId
|
|
16
|
+
} from "@cuylabs/agent-foundry-agentserver-responses";
|
|
17
|
+
function createResponsesEventState(options) {
|
|
18
|
+
return {
|
|
19
|
+
responseId: options.responseId,
|
|
20
|
+
request: options.request,
|
|
21
|
+
createdAt: options.createdAt,
|
|
22
|
+
outputIndex: 0,
|
|
23
|
+
contentIndex: 0,
|
|
24
|
+
fullText: "",
|
|
25
|
+
outputItems: [],
|
|
26
|
+
terminal: false
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function createResponseLifecycleEvents(state) {
|
|
30
|
+
const response = createResponseObject({
|
|
31
|
+
id: state.responseId,
|
|
32
|
+
request: state.request,
|
|
33
|
+
status: "queued",
|
|
34
|
+
createdAt: state.createdAt
|
|
35
|
+
});
|
|
36
|
+
state.response = response;
|
|
37
|
+
const inProgress = { ...response, status: "in_progress" };
|
|
38
|
+
state.response = inProgress;
|
|
39
|
+
return [
|
|
40
|
+
{ type: "response.created", response },
|
|
41
|
+
{ type: "response.in_progress", response: inProgress }
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
function agentEventToResponseEvents(event, state) {
|
|
45
|
+
switch (event.type) {
|
|
46
|
+
case "text-start":
|
|
47
|
+
return ensureMessageStarted(state);
|
|
48
|
+
case "text-delta":
|
|
49
|
+
return emitTextDelta(event.text, state);
|
|
50
|
+
case "text-end":
|
|
51
|
+
return [];
|
|
52
|
+
case "tool-start":
|
|
53
|
+
return emitToolCallStarted(event, state);
|
|
54
|
+
case "tool-result":
|
|
55
|
+
return emitToolCallOutput(event.toolCallId, event.result, state);
|
|
56
|
+
case "tool-error":
|
|
57
|
+
return emitToolCallOutput(
|
|
58
|
+
event.toolCallId,
|
|
59
|
+
{ error: event.error },
|
|
60
|
+
state
|
|
61
|
+
);
|
|
62
|
+
case "approval-request":
|
|
63
|
+
return emitAgentEventOutput("approval_required", event.request, state);
|
|
64
|
+
case "human-input-request":
|
|
65
|
+
return emitAgentEventOutput("input_required", event.request, state);
|
|
66
|
+
case "error":
|
|
67
|
+
return finalizeFailed(event.error.message, state);
|
|
68
|
+
case "complete":
|
|
69
|
+
return finalizeCompleted(event.output, event.usage, state);
|
|
70
|
+
default:
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function finalizeCompleted(output, usage, state) {
|
|
75
|
+
if (state.terminal) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const events = [];
|
|
79
|
+
if (output && !state.fullText) {
|
|
80
|
+
events.push(...emitTextDelta(output, state));
|
|
81
|
+
}
|
|
82
|
+
events.push(...finishMessage(state));
|
|
83
|
+
const response = {
|
|
84
|
+
...state.response ?? createResponseObject({
|
|
85
|
+
id: state.responseId,
|
|
86
|
+
request: state.request,
|
|
87
|
+
status: "in_progress",
|
|
88
|
+
createdAt: state.createdAt
|
|
89
|
+
}),
|
|
90
|
+
status: "completed",
|
|
91
|
+
output: state.outputItems,
|
|
92
|
+
error: null,
|
|
93
|
+
usage: usage ? {
|
|
94
|
+
input_tokens: usage.inputTokens,
|
|
95
|
+
output_tokens: usage.outputTokens,
|
|
96
|
+
total_tokens: usage.totalTokens
|
|
97
|
+
} : void 0
|
|
98
|
+
};
|
|
99
|
+
state.response = response;
|
|
100
|
+
state.terminal = true;
|
|
101
|
+
events.push({ type: "response.completed", response });
|
|
102
|
+
return events;
|
|
103
|
+
}
|
|
104
|
+
function finalizeFailed(message, state) {
|
|
105
|
+
if (state.terminal) {
|
|
106
|
+
return [];
|
|
107
|
+
}
|
|
108
|
+
const response = {
|
|
109
|
+
...state.response ?? createResponseObject({
|
|
110
|
+
id: state.responseId,
|
|
111
|
+
request: state.request,
|
|
112
|
+
status: "in_progress",
|
|
113
|
+
createdAt: state.createdAt
|
|
114
|
+
}),
|
|
115
|
+
status: "failed",
|
|
116
|
+
error: {
|
|
117
|
+
code: "server_error",
|
|
118
|
+
message,
|
|
119
|
+
type: "server_error"
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
state.response = response;
|
|
123
|
+
state.terminal = true;
|
|
124
|
+
return [{ type: "response.failed", response }];
|
|
125
|
+
}
|
|
126
|
+
function finalizeCancelled(state) {
|
|
127
|
+
if (state.terminal) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
const response = {
|
|
131
|
+
...state.response ?? createResponseObject({
|
|
132
|
+
id: state.responseId,
|
|
133
|
+
request: state.request,
|
|
134
|
+
status: "in_progress",
|
|
135
|
+
createdAt: state.createdAt
|
|
136
|
+
}),
|
|
137
|
+
status: "cancelled",
|
|
138
|
+
error: null
|
|
139
|
+
};
|
|
140
|
+
state.response = response;
|
|
141
|
+
state.terminal = true;
|
|
142
|
+
return [{ type: "response.cancelled", response }];
|
|
143
|
+
}
|
|
144
|
+
function coalesceResponseAgentEvents(previous, next) {
|
|
145
|
+
if (previous.type === "text-delta" && next.type === "text-delta") {
|
|
146
|
+
return {
|
|
147
|
+
type: "text-delta",
|
|
148
|
+
text: previous.text + next.text
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return void 0;
|
|
152
|
+
}
|
|
153
|
+
function emitTextDelta(text, state) {
|
|
154
|
+
if (!text) {
|
|
155
|
+
return [];
|
|
156
|
+
}
|
|
157
|
+
const events = ensureMessageStarted(state);
|
|
158
|
+
state.fullText += text;
|
|
159
|
+
events.push({
|
|
160
|
+
type: "response.output_text.delta",
|
|
161
|
+
output_index: state.messageOutputIndex ?? 0,
|
|
162
|
+
content_index: 0,
|
|
163
|
+
item_id: state.message?.id,
|
|
164
|
+
delta: text
|
|
165
|
+
});
|
|
166
|
+
return events;
|
|
167
|
+
}
|
|
168
|
+
function ensureMessageStarted(state) {
|
|
169
|
+
if (state.message) {
|
|
170
|
+
return [];
|
|
171
|
+
}
|
|
172
|
+
const part = {
|
|
173
|
+
type: "output_text",
|
|
174
|
+
text: "",
|
|
175
|
+
annotations: []
|
|
176
|
+
};
|
|
177
|
+
const item = {
|
|
178
|
+
id: newOutputMessageItemId(state.responseId),
|
|
179
|
+
type: "message",
|
|
180
|
+
status: "in_progress",
|
|
181
|
+
role: "assistant",
|
|
182
|
+
content: [part]
|
|
183
|
+
};
|
|
184
|
+
const outputIndex = appendOutputItem(state, item);
|
|
185
|
+
state.message = item;
|
|
186
|
+
state.messageOutputIndex = outputIndex;
|
|
187
|
+
return [
|
|
188
|
+
{
|
|
189
|
+
type: "response.output_item.added",
|
|
190
|
+
output_index: outputIndex,
|
|
191
|
+
item
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
type: "response.content_part.added",
|
|
195
|
+
output_index: outputIndex,
|
|
196
|
+
content_index: 0,
|
|
197
|
+
item_id: item.id,
|
|
198
|
+
part
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
}
|
|
202
|
+
function finishMessage(state) {
|
|
203
|
+
const message = state.message;
|
|
204
|
+
if (!message) {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
const outputIndex = state.messageOutputIndex ?? 0;
|
|
208
|
+
const part = message.content?.[0];
|
|
209
|
+
if (part?.type === "output_text") {
|
|
210
|
+
part.text = state.fullText;
|
|
211
|
+
}
|
|
212
|
+
message.status = "completed";
|
|
213
|
+
return [
|
|
214
|
+
{
|
|
215
|
+
type: "response.output_text.done",
|
|
216
|
+
output_index: outputIndex,
|
|
217
|
+
content_index: 0,
|
|
218
|
+
item_id: message.id,
|
|
219
|
+
text: state.fullText
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
type: "response.content_part.done",
|
|
223
|
+
output_index: outputIndex,
|
|
224
|
+
content_index: 0,
|
|
225
|
+
item_id: message.id,
|
|
226
|
+
part
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: "response.output_item.done",
|
|
230
|
+
output_index: outputIndex,
|
|
231
|
+
item: message
|
|
232
|
+
}
|
|
233
|
+
];
|
|
234
|
+
}
|
|
235
|
+
function emitToolCallStarted(event, state) {
|
|
236
|
+
const item = {
|
|
237
|
+
id: event.toolCallId || newId("fc", state.responseId),
|
|
238
|
+
type: "function_call",
|
|
239
|
+
status: "in_progress",
|
|
240
|
+
call_id: event.toolCallId,
|
|
241
|
+
name: event.toolName,
|
|
242
|
+
arguments: jsonText(event.input)
|
|
243
|
+
};
|
|
244
|
+
const outputIndex = appendOutputItem(state, item);
|
|
245
|
+
return [
|
|
246
|
+
{
|
|
247
|
+
type: "response.output_item.added",
|
|
248
|
+
output_index: outputIndex,
|
|
249
|
+
item
|
|
250
|
+
}
|
|
251
|
+
];
|
|
252
|
+
}
|
|
253
|
+
function emitToolCallOutput(callId, result, state) {
|
|
254
|
+
const item = {
|
|
255
|
+
id: newId("fcout", state.responseId),
|
|
256
|
+
type: "function_call_output",
|
|
257
|
+
status: "completed",
|
|
258
|
+
call_id: callId,
|
|
259
|
+
output: jsonText(result)
|
|
260
|
+
};
|
|
261
|
+
const outputIndex = appendOutputItem(state, item);
|
|
262
|
+
return [
|
|
263
|
+
{
|
|
264
|
+
type: "response.output_item.done",
|
|
265
|
+
output_index: outputIndex,
|
|
266
|
+
item
|
|
267
|
+
}
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
function emitAgentEventOutput(type, payload, state) {
|
|
271
|
+
const item = {
|
|
272
|
+
id: newId("item", state.responseId),
|
|
273
|
+
type,
|
|
274
|
+
status: "completed",
|
|
275
|
+
payload
|
|
276
|
+
};
|
|
277
|
+
const outputIndex = appendOutputItem(state, item);
|
|
278
|
+
return [
|
|
279
|
+
{
|
|
280
|
+
type: "response.output_item.done",
|
|
281
|
+
output_index: outputIndex,
|
|
282
|
+
item
|
|
283
|
+
}
|
|
284
|
+
];
|
|
285
|
+
}
|
|
286
|
+
function appendOutputItem(state, item) {
|
|
287
|
+
const outputIndex = state.outputItems.length;
|
|
288
|
+
state.outputItems.push(item);
|
|
289
|
+
state.outputIndex = outputIndex + 1;
|
|
290
|
+
return outputIndex;
|
|
291
|
+
}
|
|
292
|
+
function jsonText(value) {
|
|
293
|
+
if (typeof value === "string") {
|
|
294
|
+
return value;
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
return JSON.stringify(value);
|
|
298
|
+
} catch {
|
|
299
|
+
return String(value);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// src/responses/index.ts
|
|
304
|
+
var DEFAULT_EMPTY_INPUT_MESSAGE = "Send a non-empty input string or message item to create a response.";
|
|
305
|
+
function createResponsesHandlerForAgent(server, options = {}) {
|
|
306
|
+
return new AgentCoreResponsesHandler(server, options);
|
|
307
|
+
}
|
|
308
|
+
var AgentCoreResponsesHandler = class extends ResponsesHandler {
|
|
309
|
+
constructor(server, options) {
|
|
310
|
+
super();
|
|
311
|
+
this.server = server;
|
|
312
|
+
this.options = options;
|
|
313
|
+
}
|
|
314
|
+
async handle(request, context, signal) {
|
|
315
|
+
const message = (await context.getInputText()).trim();
|
|
316
|
+
if (!message) {
|
|
317
|
+
return new TextResponse(context, request, {
|
|
318
|
+
text: this.options.emptyInputMessage ?? DEFAULT_EMPTY_INPUT_MESSAGE
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return this.streamAgentTurn(request, context, signal, message);
|
|
322
|
+
}
|
|
323
|
+
async close() {
|
|
324
|
+
await this.server.close?.();
|
|
325
|
+
}
|
|
326
|
+
async *streamAgentTurn(request, context, signal, message) {
|
|
327
|
+
const startedAt = Date.now();
|
|
328
|
+
const state = createResponsesEventState({
|
|
329
|
+
responseId: context.responseId,
|
|
330
|
+
request,
|
|
331
|
+
createdAt: context.createdAt
|
|
332
|
+
});
|
|
333
|
+
for (const event of createResponseLifecycleEvents(state)) {
|
|
334
|
+
yield event;
|
|
335
|
+
}
|
|
336
|
+
let turnId;
|
|
337
|
+
let unsubscribe;
|
|
338
|
+
let abortListener;
|
|
339
|
+
try {
|
|
340
|
+
const turn = await this.server.startTurn(context.sessionId, message, {
|
|
341
|
+
...typeof request.instructions === "string" ? { system: request.instructions } : {}
|
|
342
|
+
});
|
|
343
|
+
turnId = turn.id;
|
|
344
|
+
const queue = new AsyncQueue();
|
|
345
|
+
const deliveredSequences = /* @__PURE__ */ new Set();
|
|
346
|
+
unsubscribe = this.server.subscribe(
|
|
347
|
+
(notification) => {
|
|
348
|
+
if (notification.type === "turn/event") {
|
|
349
|
+
deliveredSequences.add(notification.sequence);
|
|
350
|
+
queue.push(
|
|
351
|
+
{
|
|
352
|
+
kind: "event",
|
|
353
|
+
event: notification.event,
|
|
354
|
+
sequence: notification.sequence
|
|
355
|
+
},
|
|
356
|
+
coalesceQueueItems
|
|
357
|
+
);
|
|
358
|
+
} else if (notification.type === "turn/completed") {
|
|
359
|
+
queue.push({ kind: "completed", turn: notification.turn });
|
|
360
|
+
queue.close();
|
|
361
|
+
}
|
|
362
|
+
},
|
|
363
|
+
{ turnId: turn.id }
|
|
364
|
+
);
|
|
365
|
+
abortListener = () => {
|
|
366
|
+
this.server.interruptTurn(turn.id);
|
|
367
|
+
};
|
|
368
|
+
signal.addEventListener("abort", abortListener, { once: true });
|
|
369
|
+
const existing = this.server.getTurn(turn.id);
|
|
370
|
+
for (const record of existing?.events ?? []) {
|
|
371
|
+
if (deliveredSequences.has(record.sequence)) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
deliveredSequences.add(record.sequence);
|
|
375
|
+
queue.push(
|
|
376
|
+
{
|
|
377
|
+
kind: "event",
|
|
378
|
+
event: record.event,
|
|
379
|
+
sequence: record.sequence
|
|
380
|
+
},
|
|
381
|
+
coalesceQueueItems
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
if (existing && existing.status !== "running") {
|
|
385
|
+
queue.push({ kind: "completed", turn: existing });
|
|
386
|
+
queue.close();
|
|
387
|
+
}
|
|
388
|
+
for await (const item of queue) {
|
|
389
|
+
if (item.kind === "event") {
|
|
390
|
+
for (const event of agentEventToResponseEvents(item.event, state)) {
|
|
391
|
+
yield event;
|
|
392
|
+
}
|
|
393
|
+
continue;
|
|
394
|
+
}
|
|
395
|
+
if (item.turn.status === "completed") {
|
|
396
|
+
for (const event of finalizeCompleted(
|
|
397
|
+
item.turn.output,
|
|
398
|
+
item.turn.usage,
|
|
399
|
+
state
|
|
400
|
+
)) {
|
|
401
|
+
yield event;
|
|
402
|
+
}
|
|
403
|
+
await this.fireOnTurnComplete({
|
|
404
|
+
responseId: context.responseId,
|
|
405
|
+
sessionId: context.sessionId,
|
|
406
|
+
turnId: item.turn.id,
|
|
407
|
+
fullText: state.fullText,
|
|
408
|
+
durationMs: Date.now() - startedAt,
|
|
409
|
+
status: "ok"
|
|
410
|
+
});
|
|
411
|
+
} else if (item.turn.status === "interrupted" || signal.aborted) {
|
|
412
|
+
for (const event of finalizeCancelled(state)) {
|
|
413
|
+
yield event;
|
|
414
|
+
}
|
|
415
|
+
await this.fireOnTurnComplete({
|
|
416
|
+
responseId: context.responseId,
|
|
417
|
+
sessionId: context.sessionId,
|
|
418
|
+
turnId: item.turn.id,
|
|
419
|
+
fullText: state.fullText,
|
|
420
|
+
durationMs: Date.now() - startedAt,
|
|
421
|
+
status: "cancelled"
|
|
422
|
+
});
|
|
423
|
+
} else {
|
|
424
|
+
const error = item.turn.error ?? "Agent turn failed";
|
|
425
|
+
for (const event of finalizeFailed(error, state)) {
|
|
426
|
+
yield event;
|
|
427
|
+
}
|
|
428
|
+
await this.fireOnTurnComplete({
|
|
429
|
+
responseId: context.responseId,
|
|
430
|
+
sessionId: context.sessionId,
|
|
431
|
+
turnId: item.turn.id,
|
|
432
|
+
fullText: state.fullText,
|
|
433
|
+
durationMs: Date.now() - startedAt,
|
|
434
|
+
status: "error",
|
|
435
|
+
error
|
|
436
|
+
});
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
} catch (error) {
|
|
440
|
+
const message2 = error instanceof Error ? error.message : String(error);
|
|
441
|
+
this.options.logger?.error("responses turn failed", {
|
|
442
|
+
responseId: context.responseId,
|
|
443
|
+
sessionId: context.sessionId,
|
|
444
|
+
...turnId ? { turnId } : {},
|
|
445
|
+
error: message2
|
|
446
|
+
});
|
|
447
|
+
for (const event of finalizeFailed(message2, state)) {
|
|
448
|
+
yield event;
|
|
449
|
+
}
|
|
450
|
+
await this.fireOnTurnComplete({
|
|
451
|
+
responseId: context.responseId,
|
|
452
|
+
sessionId: context.sessionId,
|
|
453
|
+
...turnId ? { turnId } : {},
|
|
454
|
+
fullText: state.fullText,
|
|
455
|
+
durationMs: Date.now() - startedAt,
|
|
456
|
+
status: "error",
|
|
457
|
+
error: message2
|
|
458
|
+
});
|
|
459
|
+
} finally {
|
|
460
|
+
if (abortListener) {
|
|
461
|
+
signal.removeEventListener("abort", abortListener);
|
|
462
|
+
}
|
|
463
|
+
unsubscribe?.();
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
async fireOnTurnComplete(summary) {
|
|
467
|
+
if (!this.options.onTurnComplete) {
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
470
|
+
try {
|
|
471
|
+
await this.options.onTurnComplete(summary);
|
|
472
|
+
} catch {
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
function coalesceQueueItems(previous, next) {
|
|
477
|
+
if (previous.kind !== "event" || next.kind !== "event") {
|
|
478
|
+
return void 0;
|
|
479
|
+
}
|
|
480
|
+
const event = coalesceResponseAgentEvents(previous.event, next.event);
|
|
481
|
+
return event ? { kind: "event", event } : void 0;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
export {
|
|
485
|
+
createResponsesEventState,
|
|
486
|
+
createResponseLifecycleEvents,
|
|
487
|
+
agentEventToResponseEvents,
|
|
488
|
+
finalizeCompleted,
|
|
489
|
+
finalizeFailed,
|
|
490
|
+
finalizeCancelled,
|
|
491
|
+
coalesceResponseAgentEvents,
|
|
492
|
+
createResponsesHandlerForAgent
|
|
493
|
+
};
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AsyncQueue
|
|
3
|
+
} from "./chunk-BK7IBLJL.js";
|
|
4
|
+
|
|
1
5
|
// src/invocations/index.ts
|
|
2
6
|
import {
|
|
3
7
|
InvocationHandler,
|
|
@@ -7,64 +11,6 @@ import {
|
|
|
7
11
|
writeErrorFrame
|
|
8
12
|
} from "@cuylabs/agent-foundry-agentserver-invocations";
|
|
9
13
|
|
|
10
|
-
// src/invocations/async-queue.ts
|
|
11
|
-
var AsyncQueue = class {
|
|
12
|
-
values = [];
|
|
13
|
-
waiters = [];
|
|
14
|
-
closed = false;
|
|
15
|
-
push(value, coalesce) {
|
|
16
|
-
if (this.closed) {
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
const waiter = this.waiters.shift();
|
|
20
|
-
if (waiter) {
|
|
21
|
-
waiter({ value, done: false });
|
|
22
|
-
return;
|
|
23
|
-
}
|
|
24
|
-
if (coalesce && this.values.length > 0) {
|
|
25
|
-
const lastIndex = this.values.length - 1;
|
|
26
|
-
const merged = coalesce(this.values[lastIndex], value);
|
|
27
|
-
if (merged !== void 0) {
|
|
28
|
-
this.values[lastIndex] = merged;
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
this.values.push(value);
|
|
33
|
-
}
|
|
34
|
-
close() {
|
|
35
|
-
if (this.closed) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
this.closed = true;
|
|
39
|
-
for (const waiter of this.waiters.splice(0)) {
|
|
40
|
-
waiter({ value: void 0, done: true });
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
reset() {
|
|
44
|
-
this.values = [];
|
|
45
|
-
this.closed = false;
|
|
46
|
-
}
|
|
47
|
-
async *[Symbol.asyncIterator]() {
|
|
48
|
-
while (true) {
|
|
49
|
-
if (this.values.length > 0) {
|
|
50
|
-
const value = this.values.shift();
|
|
51
|
-
yield value;
|
|
52
|
-
continue;
|
|
53
|
-
}
|
|
54
|
-
if (this.closed) {
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
const result = await new Promise((resolve) => {
|
|
58
|
-
this.waiters.push(resolve);
|
|
59
|
-
});
|
|
60
|
-
if (result.done) {
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
yield result.value;
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
};
|
|
67
|
-
|
|
68
14
|
// src/invocations/events.ts
|
|
69
15
|
import {
|
|
70
16
|
sseFrame
|
|
@@ -602,7 +548,6 @@ var AgentCoreInvocationHandler = class extends InvocationHandler {
|
|
|
602
548
|
};
|
|
603
549
|
|
|
604
550
|
export {
|
|
605
|
-
AsyncQueue,
|
|
606
551
|
agentEventToSseFrame,
|
|
607
552
|
coalesceAgentEvents,
|
|
608
553
|
InvocationBroker,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { CreateInvocationsHandlerOptions, TurnSummary, createInvocationsHandlerForAgent } from './invocations/index.js';
|
|
2
|
+
export { CreateResponsesHandlerOptions, ResponsesTurnSummary, createResponsesHandlerForAgent } from './responses/index.js';
|
|
2
3
|
import '@cuylabs/agent-server';
|
|
3
4
|
import '@cuylabs/agent-foundry-agentserver-invocations';
|
|
4
5
|
import '@cuylabs/agent-core';
|
|
6
|
+
import '@cuylabs/agent-foundry-agentserver-responses';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createInvocationsHandlerForAgent
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SJJFHS66.js";
|
|
4
|
+
import {
|
|
5
|
+
createResponsesHandlerForAgent
|
|
6
|
+
} from "./chunk-M7O23JGF.js";
|
|
7
|
+
import "./chunk-BK7IBLJL.js";
|
|
4
8
|
export {
|
|
5
|
-
createInvocationsHandlerForAgent
|
|
9
|
+
createInvocationsHandlerForAgent,
|
|
10
|
+
createResponsesHandlerForAgent
|
|
6
11
|
};
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AsyncQueue,
|
|
3
2
|
InvocationBroker,
|
|
4
3
|
agentEventToSseFrame,
|
|
5
4
|
coalesceAgentEvents,
|
|
6
5
|
createInvocationsHandlerForAgent
|
|
7
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-SJJFHS66.js";
|
|
7
|
+
import {
|
|
8
|
+
AsyncQueue
|
|
9
|
+
} from "../chunk-BK7IBLJL.js";
|
|
8
10
|
export {
|
|
9
11
|
AsyncQueue,
|
|
10
12
|
InvocationBroker,
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { InProcessAgentServer } from '@cuylabs/agent-server';
|
|
2
|
+
import { CreateResponse, OutputItem, ResponseObject, ResponseStreamEvent, ResponsesHandler } from '@cuylabs/agent-foundry-agentserver-responses';
|
|
3
|
+
import { AgentEvent, TokenUsage } from '@cuylabs/agent-core';
|
|
4
|
+
|
|
5
|
+
interface ResponsesEventState {
|
|
6
|
+
responseId: string;
|
|
7
|
+
request: CreateResponse;
|
|
8
|
+
createdAt: number;
|
|
9
|
+
outputIndex: number;
|
|
10
|
+
contentIndex: number;
|
|
11
|
+
fullText: string;
|
|
12
|
+
message?: OutputItem;
|
|
13
|
+
messageOutputIndex?: number;
|
|
14
|
+
outputItems: OutputItem[];
|
|
15
|
+
response?: ResponseObject;
|
|
16
|
+
terminal: boolean;
|
|
17
|
+
}
|
|
18
|
+
declare function createResponsesEventState(options: {
|
|
19
|
+
responseId: string;
|
|
20
|
+
request: CreateResponse;
|
|
21
|
+
createdAt: number;
|
|
22
|
+
}): ResponsesEventState;
|
|
23
|
+
declare function createResponseLifecycleEvents(state: ResponsesEventState): ResponseStreamEvent[];
|
|
24
|
+
declare function agentEventToResponseEvents(event: AgentEvent, state: ResponsesEventState): ResponseStreamEvent[];
|
|
25
|
+
declare function finalizeCompleted(output: string | undefined, usage: TokenUsage | undefined, state: ResponsesEventState): ResponseStreamEvent[];
|
|
26
|
+
declare function finalizeFailed(message: string, state: ResponsesEventState): ResponseStreamEvent[];
|
|
27
|
+
declare function finalizeCancelled(state: ResponsesEventState): ResponseStreamEvent[];
|
|
28
|
+
declare function coalesceResponseAgentEvents(previous: AgentEvent, next: AgentEvent): AgentEvent | undefined;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* @cuylabs/agent-foundry-hosting/responses
|
|
32
|
+
*
|
|
33
|
+
* Bridge from a `@cuylabs/agent-server` `InProcessAgentServer` to the
|
|
34
|
+
* Foundry Responses protocol.
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
interface CreateResponsesHandlerOptions {
|
|
38
|
+
emptyInputMessage?: string;
|
|
39
|
+
logger?: ResponsesBridgeLogger;
|
|
40
|
+
onTurnComplete?: (summary: ResponsesTurnSummary) => void | Promise<void>;
|
|
41
|
+
}
|
|
42
|
+
interface ResponsesBridgeLogger {
|
|
43
|
+
info(message: string, meta?: Record<string, unknown>): void;
|
|
44
|
+
warn(message: string, meta?: Record<string, unknown>): void;
|
|
45
|
+
error(message: string, meta?: Record<string, unknown>): void;
|
|
46
|
+
debug?(message: string, meta?: Record<string, unknown>): void;
|
|
47
|
+
}
|
|
48
|
+
interface ResponsesTurnSummary {
|
|
49
|
+
responseId: string;
|
|
50
|
+
sessionId: string;
|
|
51
|
+
turnId?: string;
|
|
52
|
+
fullText: string;
|
|
53
|
+
durationMs: number;
|
|
54
|
+
status: "ok" | "error" | "cancelled";
|
|
55
|
+
error?: string;
|
|
56
|
+
}
|
|
57
|
+
declare function createResponsesHandlerForAgent(server: InProcessAgentServer, options?: CreateResponsesHandlerOptions): ResponsesHandler;
|
|
58
|
+
|
|
59
|
+
export { type CreateResponsesHandlerOptions, type ResponsesBridgeLogger, type ResponsesEventState, type ResponsesTurnSummary, agentEventToResponseEvents, coalesceResponseAgentEvents, createResponseLifecycleEvents, createResponsesEventState, createResponsesHandlerForAgent, finalizeCancelled, finalizeCompleted, finalizeFailed };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
agentEventToResponseEvents,
|
|
3
|
+
coalesceResponseAgentEvents,
|
|
4
|
+
createResponseLifecycleEvents,
|
|
5
|
+
createResponsesEventState,
|
|
6
|
+
createResponsesHandlerForAgent,
|
|
7
|
+
finalizeCancelled,
|
|
8
|
+
finalizeCompleted,
|
|
9
|
+
finalizeFailed
|
|
10
|
+
} from "../chunk-M7O23JGF.js";
|
|
11
|
+
import "../chunk-BK7IBLJL.js";
|
|
12
|
+
export {
|
|
13
|
+
agentEventToResponseEvents,
|
|
14
|
+
coalesceResponseAgentEvents,
|
|
15
|
+
createResponseLifecycleEvents,
|
|
16
|
+
createResponsesEventState,
|
|
17
|
+
createResponsesHandlerForAgent,
|
|
18
|
+
finalizeCancelled,
|
|
19
|
+
finalizeCompleted,
|
|
20
|
+
finalizeFailed
|
|
21
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cuylabs/agent-foundry-hosting",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.9.0",
|
|
4
4
|
"description": "Foundry Hosting integration for @cuylabs/agent-core (agent-core ↔ Invocations protocol bridge; mirrors agent-framework-foundry-hosting)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
"types": "./dist/invocations/index.d.ts",
|
|
16
16
|
"import": "./dist/invocations/index.js",
|
|
17
17
|
"default": "./dist/invocations/index.js"
|
|
18
|
+
},
|
|
19
|
+
"./responses": {
|
|
20
|
+
"types": "./dist/responses/index.d.ts",
|
|
21
|
+
"import": "./dist/responses/index.js",
|
|
22
|
+
"default": "./dist/responses/index.js"
|
|
18
23
|
}
|
|
19
24
|
},
|
|
20
25
|
"files": [
|
|
@@ -27,14 +32,16 @@
|
|
|
27
32
|
"tsup": "^8.0.0",
|
|
28
33
|
"typescript": "^5.7.0",
|
|
29
34
|
"vitest": "^4.0.18",
|
|
30
|
-
"@cuylabs/agent-core": "^4.
|
|
31
|
-
"@cuylabs/agent-server": "^4.
|
|
32
|
-
"@cuylabs/agent-foundry-agentserver-
|
|
35
|
+
"@cuylabs/agent-core": "^4.9.0",
|
|
36
|
+
"@cuylabs/agent-server": "^4.9.0",
|
|
37
|
+
"@cuylabs/agent-foundry-agentserver-responses": "^4.9.0",
|
|
38
|
+
"@cuylabs/agent-foundry-agentserver-invocations": "^4.9.0"
|
|
33
39
|
},
|
|
34
40
|
"peerDependencies": {
|
|
35
|
-
"@cuylabs/agent-core": "^4.
|
|
36
|
-
"@cuylabs/agent-server": "^4.
|
|
37
|
-
"@cuylabs/agent-foundry-agentserver-
|
|
41
|
+
"@cuylabs/agent-core": "^4.9.0",
|
|
42
|
+
"@cuylabs/agent-server": "^4.9.0",
|
|
43
|
+
"@cuylabs/agent-foundry-agentserver-responses": "^4.9.0",
|
|
44
|
+
"@cuylabs/agent-foundry-agentserver-invocations": "^4.9.0"
|
|
38
45
|
},
|
|
39
46
|
"keywords": [
|
|
40
47
|
"agent",
|
|
@@ -58,8 +65,8 @@
|
|
|
58
65
|
"access": "public"
|
|
59
66
|
},
|
|
60
67
|
"scripts": {
|
|
61
|
-
"build": "tsup src/index.ts src/invocations/index.ts --format esm --dts --clean",
|
|
62
|
-
"dev": "tsup src/index.ts src/invocations/index.ts --format esm --dts --watch",
|
|
68
|
+
"build": "tsup src/index.ts src/invocations/index.ts src/responses/index.ts --format esm --dts --clean",
|
|
69
|
+
"dev": "tsup src/index.ts src/invocations/index.ts src/responses/index.ts --format esm --dts --watch",
|
|
63
70
|
"typecheck": "tsc --noEmit",
|
|
64
71
|
"test": "vitest run",
|
|
65
72
|
"test:watch": "vitest",
|