@diologue/local-agent 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/cli.mjs +489 -1
- package/dist/cli.mjs.map +4 -4
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -1351,6 +1351,366 @@ var translateResponse = (response, id, modelEcho) => {
|
|
|
1351
1351
|
};
|
|
1352
1352
|
};
|
|
1353
1353
|
|
|
1354
|
+
// src/shim/responses-translator.ts
|
|
1355
|
+
var flattenContent = (content) => {
|
|
1356
|
+
if (typeof content === "string") return content;
|
|
1357
|
+
return content.map((part) => {
|
|
1358
|
+
if (part.type === "input_text" || part.type === "output_text") {
|
|
1359
|
+
return part.text ?? "";
|
|
1360
|
+
}
|
|
1361
|
+
return "";
|
|
1362
|
+
}).join("");
|
|
1363
|
+
};
|
|
1364
|
+
var responsesToChatCompletions = (req) => {
|
|
1365
|
+
const messages = [];
|
|
1366
|
+
for (const item of req.input) {
|
|
1367
|
+
if ("type" in item && item.type === "function_call") {
|
|
1368
|
+
messages.push({
|
|
1369
|
+
role: "assistant",
|
|
1370
|
+
content: null,
|
|
1371
|
+
tool_calls: [
|
|
1372
|
+
{
|
|
1373
|
+
id: item.call_id,
|
|
1374
|
+
type: "function",
|
|
1375
|
+
function: { name: item.name, arguments: item.arguments }
|
|
1376
|
+
}
|
|
1377
|
+
]
|
|
1378
|
+
});
|
|
1379
|
+
continue;
|
|
1380
|
+
}
|
|
1381
|
+
if ("type" in item && item.type === "function_call_output") {
|
|
1382
|
+
messages.push({
|
|
1383
|
+
role: "tool",
|
|
1384
|
+
content: item.output,
|
|
1385
|
+
tool_call_id: item.call_id
|
|
1386
|
+
});
|
|
1387
|
+
continue;
|
|
1388
|
+
}
|
|
1389
|
+
const role = item.role;
|
|
1390
|
+
const content = flattenContent(item.content);
|
|
1391
|
+
messages.push({ role, content });
|
|
1392
|
+
}
|
|
1393
|
+
const tools = req.tools?.map((t) => ({
|
|
1394
|
+
type: "function",
|
|
1395
|
+
function: {
|
|
1396
|
+
name: t.name,
|
|
1397
|
+
description: t.description,
|
|
1398
|
+
parameters: t.parameters
|
|
1399
|
+
}
|
|
1400
|
+
}));
|
|
1401
|
+
let toolChoice;
|
|
1402
|
+
if (typeof req.tool_choice === "string") {
|
|
1403
|
+
toolChoice = req.tool_choice;
|
|
1404
|
+
} else if (req.tool_choice && typeof req.tool_choice === "object") {
|
|
1405
|
+
toolChoice = {
|
|
1406
|
+
type: "function",
|
|
1407
|
+
function: { name: req.tool_choice.name }
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
return {
|
|
1411
|
+
model: req.model,
|
|
1412
|
+
messages,
|
|
1413
|
+
tools,
|
|
1414
|
+
tool_choice: toolChoice,
|
|
1415
|
+
temperature: req.temperature,
|
|
1416
|
+
stream: req.stream,
|
|
1417
|
+
// Pass max_output_tokens through as max_tokens for downstream
|
|
1418
|
+
// providers that honour it. Chat Completions naming.
|
|
1419
|
+
max_tokens: req.max_output_tokens
|
|
1420
|
+
};
|
|
1421
|
+
};
|
|
1422
|
+
var randomId = (prefix) => `${prefix}_${Math.random().toString(36).slice(2, 12)}`;
|
|
1423
|
+
var ResponsesStreamState = class {
|
|
1424
|
+
responseId;
|
|
1425
|
+
model;
|
|
1426
|
+
createdAt;
|
|
1427
|
+
outputIndex = 0;
|
|
1428
|
+
/** Open message item carrying assistant text, if any. */
|
|
1429
|
+
text = null;
|
|
1430
|
+
/** Open function_call items, keyed by the broker's tool_call index
|
|
1431
|
+
* (the model's call position, not our output_index). */
|
|
1432
|
+
tools = /* @__PURE__ */ new Map();
|
|
1433
|
+
finished = false;
|
|
1434
|
+
/** Set when broker emits `complete`. We carry usage + finish_reason
|
|
1435
|
+
* into the final response.completed payload. */
|
|
1436
|
+
finalUsage;
|
|
1437
|
+
finalStatus = "completed";
|
|
1438
|
+
constructor(model, id) {
|
|
1439
|
+
this.responseId = id ?? randomId("resp");
|
|
1440
|
+
this.model = model;
|
|
1441
|
+
this.createdAt = Math.floor(Date.now() / 1e3);
|
|
1442
|
+
}
|
|
1443
|
+
/** Emit the response.created + response.in_progress pair. Call once
|
|
1444
|
+
* before any chunks. */
|
|
1445
|
+
start() {
|
|
1446
|
+
const responseObj = {
|
|
1447
|
+
id: this.responseId,
|
|
1448
|
+
object: "response",
|
|
1449
|
+
created_at: this.createdAt,
|
|
1450
|
+
status: "in_progress",
|
|
1451
|
+
model: this.model,
|
|
1452
|
+
output: [],
|
|
1453
|
+
usage: null
|
|
1454
|
+
};
|
|
1455
|
+
return [
|
|
1456
|
+
{ event: "response.created", data: { type: "response.created", response: responseObj } },
|
|
1457
|
+
{ event: "response.in_progress", data: { type: "response.in_progress", response: responseObj } }
|
|
1458
|
+
];
|
|
1459
|
+
}
|
|
1460
|
+
/** Translate a single broker chunk. Some chunks emit multiple events
|
|
1461
|
+
* (opening a new item requires output_item.added + content_part.added
|
|
1462
|
+
* before the delta itself). */
|
|
1463
|
+
chunk(c) {
|
|
1464
|
+
if (this.finished) return [];
|
|
1465
|
+
switch (c.type) {
|
|
1466
|
+
case "text_delta":
|
|
1467
|
+
return this.handleTextDelta(c.text);
|
|
1468
|
+
case "tool_call_delta":
|
|
1469
|
+
return this.handleToolCallDelta(c);
|
|
1470
|
+
case "complete":
|
|
1471
|
+
{
|
|
1472
|
+
const tu = c.payload?.tokenUsage;
|
|
1473
|
+
if (tu) {
|
|
1474
|
+
const input = tu.input ?? 0;
|
|
1475
|
+
const output = tu.output ?? 0;
|
|
1476
|
+
this.finalUsage = {
|
|
1477
|
+
input_tokens: input,
|
|
1478
|
+
output_tokens: output,
|
|
1479
|
+
total_tokens: input + output
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
return [];
|
|
1484
|
+
case "error":
|
|
1485
|
+
this.finalStatus = "failed";
|
|
1486
|
+
return [];
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
/** Close any open items + emit the terminal response.completed event. */
|
|
1490
|
+
finish() {
|
|
1491
|
+
if (this.finished) return [];
|
|
1492
|
+
this.finished = true;
|
|
1493
|
+
const out = [];
|
|
1494
|
+
out.push(...this.closeTextItem());
|
|
1495
|
+
out.push(...this.closeAllToolItems());
|
|
1496
|
+
const responseObj = {
|
|
1497
|
+
id: this.responseId,
|
|
1498
|
+
object: "response",
|
|
1499
|
+
created_at: this.createdAt,
|
|
1500
|
+
status: this.finalStatus,
|
|
1501
|
+
model: this.model,
|
|
1502
|
+
output: [],
|
|
1503
|
+
// For brevity — the AI SDK only needs status + usage at completion.
|
|
1504
|
+
usage: this.finalUsage ?? null
|
|
1505
|
+
};
|
|
1506
|
+
out.push({
|
|
1507
|
+
event: "response.completed",
|
|
1508
|
+
data: { type: "response.completed", response: responseObj }
|
|
1509
|
+
});
|
|
1510
|
+
return out;
|
|
1511
|
+
}
|
|
1512
|
+
// ---- internals ----
|
|
1513
|
+
handleTextDelta(text) {
|
|
1514
|
+
if (!this.text) {
|
|
1515
|
+
const itemId = randomId("msg");
|
|
1516
|
+
const outputIndex = this.outputIndex++;
|
|
1517
|
+
const contentIndex = 0;
|
|
1518
|
+
this.text = { itemId, outputIndex, contentIndex, buffer: text };
|
|
1519
|
+
return [
|
|
1520
|
+
{
|
|
1521
|
+
event: "response.output_item.added",
|
|
1522
|
+
data: {
|
|
1523
|
+
type: "response.output_item.added",
|
|
1524
|
+
output_index: outputIndex,
|
|
1525
|
+
item: {
|
|
1526
|
+
id: itemId,
|
|
1527
|
+
type: "message",
|
|
1528
|
+
status: "in_progress",
|
|
1529
|
+
role: "assistant",
|
|
1530
|
+
content: []
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
},
|
|
1534
|
+
{
|
|
1535
|
+
event: "response.content_part.added",
|
|
1536
|
+
data: {
|
|
1537
|
+
type: "response.content_part.added",
|
|
1538
|
+
item_id: itemId,
|
|
1539
|
+
output_index: outputIndex,
|
|
1540
|
+
content_index: contentIndex,
|
|
1541
|
+
part: { type: "output_text", text: "" }
|
|
1542
|
+
}
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
event: "response.output_text.delta",
|
|
1546
|
+
data: {
|
|
1547
|
+
type: "response.output_text.delta",
|
|
1548
|
+
item_id: itemId,
|
|
1549
|
+
output_index: outputIndex,
|
|
1550
|
+
content_index: contentIndex,
|
|
1551
|
+
delta: text
|
|
1552
|
+
}
|
|
1553
|
+
}
|
|
1554
|
+
];
|
|
1555
|
+
}
|
|
1556
|
+
this.text.buffer += text;
|
|
1557
|
+
return [
|
|
1558
|
+
{
|
|
1559
|
+
event: "response.output_text.delta",
|
|
1560
|
+
data: {
|
|
1561
|
+
type: "response.output_text.delta",
|
|
1562
|
+
item_id: this.text.itemId,
|
|
1563
|
+
output_index: this.text.outputIndex,
|
|
1564
|
+
content_index: this.text.contentIndex,
|
|
1565
|
+
delta: text
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
];
|
|
1569
|
+
}
|
|
1570
|
+
handleToolCallDelta(c) {
|
|
1571
|
+
const events = [];
|
|
1572
|
+
events.push(...this.closeTextItem());
|
|
1573
|
+
let entry = this.tools.get(c.index);
|
|
1574
|
+
if (!entry) {
|
|
1575
|
+
entry = {
|
|
1576
|
+
itemId: randomId("fc"),
|
|
1577
|
+
outputIndex: this.outputIndex++,
|
|
1578
|
+
callId: c.id ?? randomId("call"),
|
|
1579
|
+
name: c.name ?? "",
|
|
1580
|
+
arguments: "",
|
|
1581
|
+
emittedAdded: false
|
|
1582
|
+
};
|
|
1583
|
+
this.tools.set(c.index, entry);
|
|
1584
|
+
} else {
|
|
1585
|
+
if (c.id) entry.callId = c.id;
|
|
1586
|
+
if (c.name) entry.name = c.name;
|
|
1587
|
+
}
|
|
1588
|
+
if (!entry.emittedAdded && entry.name) {
|
|
1589
|
+
entry.emittedAdded = true;
|
|
1590
|
+
events.push({
|
|
1591
|
+
event: "response.output_item.added",
|
|
1592
|
+
data: {
|
|
1593
|
+
type: "response.output_item.added",
|
|
1594
|
+
output_index: entry.outputIndex,
|
|
1595
|
+
item: {
|
|
1596
|
+
id: entry.itemId,
|
|
1597
|
+
type: "function_call",
|
|
1598
|
+
status: "in_progress",
|
|
1599
|
+
name: entry.name,
|
|
1600
|
+
call_id: entry.callId,
|
|
1601
|
+
arguments: ""
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
if (c.argumentsDelta !== void 0 && c.argumentsDelta.length > 0) {
|
|
1607
|
+
entry.arguments += c.argumentsDelta;
|
|
1608
|
+
if (entry.emittedAdded) {
|
|
1609
|
+
events.push({
|
|
1610
|
+
event: "response.function_call_arguments.delta",
|
|
1611
|
+
data: {
|
|
1612
|
+
type: "response.function_call_arguments.delta",
|
|
1613
|
+
item_id: entry.itemId,
|
|
1614
|
+
output_index: entry.outputIndex,
|
|
1615
|
+
delta: c.argumentsDelta
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
return events;
|
|
1621
|
+
}
|
|
1622
|
+
closeTextItem() {
|
|
1623
|
+
if (!this.text) return [];
|
|
1624
|
+
const { itemId, outputIndex, contentIndex, buffer } = this.text;
|
|
1625
|
+
this.text = null;
|
|
1626
|
+
return [
|
|
1627
|
+
{
|
|
1628
|
+
event: "response.output_text.done",
|
|
1629
|
+
data: {
|
|
1630
|
+
type: "response.output_text.done",
|
|
1631
|
+
item_id: itemId,
|
|
1632
|
+
output_index: outputIndex,
|
|
1633
|
+
content_index: contentIndex,
|
|
1634
|
+
text: buffer
|
|
1635
|
+
}
|
|
1636
|
+
},
|
|
1637
|
+
{
|
|
1638
|
+
event: "response.content_part.done",
|
|
1639
|
+
data: {
|
|
1640
|
+
type: "response.content_part.done",
|
|
1641
|
+
item_id: itemId,
|
|
1642
|
+
output_index: outputIndex,
|
|
1643
|
+
content_index: contentIndex,
|
|
1644
|
+
part: { type: "output_text", text: buffer }
|
|
1645
|
+
}
|
|
1646
|
+
},
|
|
1647
|
+
{
|
|
1648
|
+
event: "response.output_item.done",
|
|
1649
|
+
data: {
|
|
1650
|
+
type: "response.output_item.done",
|
|
1651
|
+
output_index: outputIndex,
|
|
1652
|
+
item: {
|
|
1653
|
+
id: itemId,
|
|
1654
|
+
type: "message",
|
|
1655
|
+
status: "completed",
|
|
1656
|
+
role: "assistant",
|
|
1657
|
+
content: [{ type: "output_text", text: buffer }]
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
];
|
|
1662
|
+
}
|
|
1663
|
+
closeAllToolItems() {
|
|
1664
|
+
const out = [];
|
|
1665
|
+
for (const entry of this.tools.values()) {
|
|
1666
|
+
if (!entry.emittedAdded) {
|
|
1667
|
+
entry.emittedAdded = true;
|
|
1668
|
+
out.push({
|
|
1669
|
+
event: "response.output_item.added",
|
|
1670
|
+
data: {
|
|
1671
|
+
type: "response.output_item.added",
|
|
1672
|
+
output_index: entry.outputIndex,
|
|
1673
|
+
item: {
|
|
1674
|
+
id: entry.itemId,
|
|
1675
|
+
type: "function_call",
|
|
1676
|
+
status: "in_progress",
|
|
1677
|
+
name: entry.name || "unknown",
|
|
1678
|
+
call_id: entry.callId,
|
|
1679
|
+
arguments: ""
|
|
1680
|
+
}
|
|
1681
|
+
}
|
|
1682
|
+
});
|
|
1683
|
+
}
|
|
1684
|
+
out.push({
|
|
1685
|
+
event: "response.function_call_arguments.done",
|
|
1686
|
+
data: {
|
|
1687
|
+
type: "response.function_call_arguments.done",
|
|
1688
|
+
item_id: entry.itemId,
|
|
1689
|
+
output_index: entry.outputIndex,
|
|
1690
|
+
arguments: entry.arguments
|
|
1691
|
+
}
|
|
1692
|
+
});
|
|
1693
|
+
out.push({
|
|
1694
|
+
event: "response.output_item.done",
|
|
1695
|
+
data: {
|
|
1696
|
+
type: "response.output_item.done",
|
|
1697
|
+
output_index: entry.outputIndex,
|
|
1698
|
+
item: {
|
|
1699
|
+
id: entry.itemId,
|
|
1700
|
+
type: "function_call",
|
|
1701
|
+
status: "completed",
|
|
1702
|
+
name: entry.name || "unknown",
|
|
1703
|
+
call_id: entry.callId,
|
|
1704
|
+
arguments: entry.arguments
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
});
|
|
1708
|
+
}
|
|
1709
|
+
this.tools.clear();
|
|
1710
|
+
return out;
|
|
1711
|
+
}
|
|
1712
|
+
};
|
|
1713
|
+
|
|
1354
1714
|
// src/shim/active-broker.ts
|
|
1355
1715
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1356
1716
|
var byToken = /* @__PURE__ */ new Map();
|
|
@@ -1370,6 +1730,11 @@ var bindActiveBroker = (broker) => {
|
|
|
1370
1730
|
var getActiveBrokerByToken = (token) => {
|
|
1371
1731
|
return byToken.get(token)?.broker ?? null;
|
|
1372
1732
|
};
|
|
1733
|
+
var getOnlyActiveBroker = () => {
|
|
1734
|
+
if (byToken.size !== 1) return null;
|
|
1735
|
+
const first = byToken.values().next().value;
|
|
1736
|
+
return first?.broker ?? null;
|
|
1737
|
+
};
|
|
1373
1738
|
|
|
1374
1739
|
// src/routes/llm-shim.ts
|
|
1375
1740
|
var extractBearer = (req) => {
|
|
@@ -1391,7 +1756,7 @@ var createLlmShimRouter = () => {
|
|
|
1391
1756
|
sendOpenAIError(res, 401, "Missing Authorization bearer", "auth_error");
|
|
1392
1757
|
return;
|
|
1393
1758
|
}
|
|
1394
|
-
const broker = getActiveBrokerByToken(token);
|
|
1759
|
+
const broker = getActiveBrokerByToken(token) ?? getOnlyActiveBroker();
|
|
1395
1760
|
if (!broker) {
|
|
1396
1761
|
sendOpenAIError(
|
|
1397
1762
|
res,
|
|
@@ -1545,6 +1910,129 @@ var createLlmShimRouter = () => {
|
|
|
1545
1910
|
res.json(out);
|
|
1546
1911
|
}
|
|
1547
1912
|
);
|
|
1913
|
+
router.post("/v1/responses", async (req, res) => {
|
|
1914
|
+
const token = extractBearer(req);
|
|
1915
|
+
if (!token) {
|
|
1916
|
+
sendOpenAIError(res, 401, "Missing Authorization bearer", "auth_error");
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1919
|
+
const broker = getActiveBrokerByToken(token);
|
|
1920
|
+
if (!broker) {
|
|
1921
|
+
sendOpenAIError(
|
|
1922
|
+
res,
|
|
1923
|
+
401,
|
|
1924
|
+
"No active coding-agent stream is currently authorised on this helper.",
|
|
1925
|
+
"auth_error"
|
|
1926
|
+
);
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
const body = req.body;
|
|
1930
|
+
if (!body || typeof body !== "object" || !Array.isArray(body.input) || body.input.length === 0) {
|
|
1931
|
+
sendOpenAIError(res, 400, "input[] is required and must be non-empty");
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1934
|
+
const chatRequest = responsesToChatCompletions(body);
|
|
1935
|
+
const brokerRequest = translateRequest(chatRequest);
|
|
1936
|
+
const stream = body.stream === true;
|
|
1937
|
+
if (stream) {
|
|
1938
|
+
res.setHeader("Content-Type", "text/event-stream");
|
|
1939
|
+
res.setHeader("Cache-Control", "no-cache, no-transform");
|
|
1940
|
+
res.setHeader("Connection", "keep-alive");
|
|
1941
|
+
res.flushHeaders?.();
|
|
1942
|
+
const state = new ResponsesStreamState(body.model);
|
|
1943
|
+
const writeEvent2 = (ev) => {
|
|
1944
|
+
res.write(`event: ${ev.event}
|
|
1945
|
+
`);
|
|
1946
|
+
res.write(`data: ${JSON.stringify(ev.data)}
|
|
1947
|
+
|
|
1948
|
+
`);
|
|
1949
|
+
};
|
|
1950
|
+
for (const ev of state.start()) writeEvent2(ev);
|
|
1951
|
+
const observer = (chunk) => {
|
|
1952
|
+
for (const ev of state.chunk(chunk)) writeEvent2(ev);
|
|
1953
|
+
};
|
|
1954
|
+
try {
|
|
1955
|
+
await broker.request(brokerRequest, observer);
|
|
1956
|
+
} catch (err) {
|
|
1957
|
+
writeEvent2({
|
|
1958
|
+
event: "response.failed",
|
|
1959
|
+
data: {
|
|
1960
|
+
type: "response.failed",
|
|
1961
|
+
response: {
|
|
1962
|
+
id: `resp_${Math.random().toString(36).slice(2, 12)}`,
|
|
1963
|
+
object: "response",
|
|
1964
|
+
status: "failed",
|
|
1965
|
+
model: body.model,
|
|
1966
|
+
error: {
|
|
1967
|
+
code: "broker_error",
|
|
1968
|
+
message: err instanceof Error ? err.message : "Broker call failed"
|
|
1969
|
+
}
|
|
1970
|
+
}
|
|
1971
|
+
}
|
|
1972
|
+
});
|
|
1973
|
+
res.write("data: [DONE]\n\n");
|
|
1974
|
+
res.end();
|
|
1975
|
+
return;
|
|
1976
|
+
}
|
|
1977
|
+
for (const ev of state.finish()) writeEvent2(ev);
|
|
1978
|
+
res.write("data: [DONE]\n\n");
|
|
1979
|
+
res.end();
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
let brokerResponse;
|
|
1983
|
+
try {
|
|
1984
|
+
brokerResponse = await broker.request(brokerRequest);
|
|
1985
|
+
} catch (err) {
|
|
1986
|
+
sendOpenAIError(
|
|
1987
|
+
res,
|
|
1988
|
+
502,
|
|
1989
|
+
err instanceof Error ? err.message : "Broker call failed",
|
|
1990
|
+
"api_error"
|
|
1991
|
+
);
|
|
1992
|
+
return;
|
|
1993
|
+
}
|
|
1994
|
+
if (brokerResponse.error) {
|
|
1995
|
+
sendOpenAIError(res, 502, brokerResponse.error, "api_error");
|
|
1996
|
+
return;
|
|
1997
|
+
}
|
|
1998
|
+
const completionId = `resp_${Math.random().toString(36).slice(2, 12)}`;
|
|
1999
|
+
const chatResponse = translateResponse(
|
|
2000
|
+
brokerResponse,
|
|
2001
|
+
completionId,
|
|
2002
|
+
body.model
|
|
2003
|
+
);
|
|
2004
|
+
const text = chatResponse.choices[0]?.message?.content ?? "";
|
|
2005
|
+
const toolCalls = chatResponse.choices[0]?.message?.tool_calls ?? [];
|
|
2006
|
+
const output = [];
|
|
2007
|
+
if (text) {
|
|
2008
|
+
output.push({
|
|
2009
|
+
id: `msg_${Math.random().toString(36).slice(2, 12)}`,
|
|
2010
|
+
type: "message",
|
|
2011
|
+
status: "completed",
|
|
2012
|
+
role: "assistant",
|
|
2013
|
+
content: [{ type: "output_text", text }]
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
for (const tc of toolCalls) {
|
|
2017
|
+
output.push({
|
|
2018
|
+
id: `fc_${Math.random().toString(36).slice(2, 12)}`,
|
|
2019
|
+
type: "function_call",
|
|
2020
|
+
status: "completed",
|
|
2021
|
+
name: tc.function.name,
|
|
2022
|
+
call_id: tc.id,
|
|
2023
|
+
arguments: tc.function.arguments
|
|
2024
|
+
});
|
|
2025
|
+
}
|
|
2026
|
+
res.json({
|
|
2027
|
+
id: completionId,
|
|
2028
|
+
object: "response",
|
|
2029
|
+
created_at: Math.floor(Date.now() / 1e3),
|
|
2030
|
+
status: "completed",
|
|
2031
|
+
model: body.model,
|
|
2032
|
+
output,
|
|
2033
|
+
usage: chatResponse.usage
|
|
2034
|
+
});
|
|
2035
|
+
});
|
|
1548
2036
|
return router;
|
|
1549
2037
|
};
|
|
1550
2038
|
|