elasticdash-test 0.1.18-alpha-7 → 0.1.18-alpha-8
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.cjs +420 -392
- package/dist/interceptors/ai-interceptor.d.ts.map +1 -1
- package/dist/interceptors/ai-interceptor.js +5 -0
- package/dist/interceptors/ai-interceptor.js.map +1 -1
- package/dist/interceptors/workflow-ai.d.ts +1 -0
- package/dist/interceptors/workflow-ai.d.ts.map +1 -1
- package/dist/interceptors/workflow-ai.js +171 -147
- package/dist/interceptors/workflow-ai.js.map +1 -1
- package/package.json +1 -1
- package/src/interceptors/ai-interceptor.ts +7 -0
- package/src/interceptors/workflow-ai.ts +26 -0
package/dist/index.cjs
CHANGED
|
@@ -875,15 +875,15 @@ function normaliseMockResult(value) {
|
|
|
875
875
|
return value;
|
|
876
876
|
}
|
|
877
877
|
function resolveMock(toolName) {
|
|
878
|
-
const
|
|
879
|
-
const mocks =
|
|
878
|
+
const g5 = globalThis;
|
|
879
|
+
const mocks = g5["__ELASTICDASH_TOOL_MOCKS__"];
|
|
880
880
|
if (!mocks) return { mocked: false };
|
|
881
881
|
const entry = mocks[toolName];
|
|
882
882
|
if (!entry || entry.mode === "live") return { mocked: false };
|
|
883
|
-
if (!
|
|
884
|
-
|
|
883
|
+
if (!g5["__ELASTICDASH_TOOL_CALL_COUNTERS__"]) {
|
|
884
|
+
g5["__ELASTICDASH_TOOL_CALL_COUNTERS__"] = {};
|
|
885
885
|
}
|
|
886
|
-
const counters =
|
|
886
|
+
const counters = g5["__ELASTICDASH_TOOL_CALL_COUNTERS__"];
|
|
887
887
|
counters[toolName] = (counters[toolName] ?? 0) + 1;
|
|
888
888
|
const callNumber = counters[toolName];
|
|
889
889
|
if (entry.mode === "mock-all") {
|
|
@@ -946,8 +946,8 @@ function replaceSystemPrompt(input, newSystemPrompt) {
|
|
|
946
946
|
return input;
|
|
947
947
|
}
|
|
948
948
|
function resolvePromptMock(input) {
|
|
949
|
-
const
|
|
950
|
-
const mocks =
|
|
949
|
+
const g5 = globalThis;
|
|
950
|
+
const mocks = g5["__ELASTICDASH_PROMPT_MOCKS__"];
|
|
951
951
|
if (!mocks || Object.keys(mocks).length === 0) return void 0;
|
|
952
952
|
const systemPrompt = extractSystemPrompt(input);
|
|
953
953
|
if (systemPrompt === void 0) return void 0;
|
|
@@ -958,10 +958,10 @@ function resolvePromptMock(input) {
|
|
|
958
958
|
return replaceSystemPrompt(input, entry);
|
|
959
959
|
}
|
|
960
960
|
if (entry.mode === "live") return void 0;
|
|
961
|
-
if (!
|
|
962
|
-
|
|
961
|
+
if (!g5["__ELASTICDASH_PROMPT_CALL_COUNTERS__"]) {
|
|
962
|
+
g5["__ELASTICDASH_PROMPT_CALL_COUNTERS__"] = {};
|
|
963
963
|
}
|
|
964
|
-
const counters =
|
|
964
|
+
const counters = g5["__ELASTICDASH_PROMPT_CALL_COUNTERS__"];
|
|
965
965
|
counters[match.key] = (counters[match.key] ?? 0) + 1;
|
|
966
966
|
const callNumber = counters[match.key];
|
|
967
967
|
if (entry.mode === "replace-all") {
|
|
@@ -1024,15 +1024,15 @@ function replaceUserPrompt(input, originalText, newText) {
|
|
|
1024
1024
|
return input;
|
|
1025
1025
|
}
|
|
1026
1026
|
function resolveUserPromptMock(input) {
|
|
1027
|
-
const
|
|
1028
|
-
const mocks =
|
|
1027
|
+
const g5 = globalThis;
|
|
1028
|
+
const mocks = g5["__ELASTICDASH_USER_PROMPT_MOCKS__"];
|
|
1029
1029
|
if (!mocks || Object.keys(mocks).length === 0) return void 0;
|
|
1030
1030
|
const userPrompts = extractUserPrompts(input);
|
|
1031
1031
|
if (userPrompts.length === 0) return void 0;
|
|
1032
|
-
if (!
|
|
1033
|
-
|
|
1032
|
+
if (!g5["__ELASTICDASH_USER_PROMPT_CALL_COUNTERS__"]) {
|
|
1033
|
+
g5["__ELASTICDASH_USER_PROMPT_CALL_COUNTERS__"] = {};
|
|
1034
1034
|
}
|
|
1035
|
-
const counters =
|
|
1035
|
+
const counters = g5["__ELASTICDASH_USER_PROMPT_CALL_COUNTERS__"];
|
|
1036
1036
|
const uniqueTexts = Array.from(new Set(userPrompts));
|
|
1037
1037
|
let modified = false;
|
|
1038
1038
|
let result = input;
|
|
@@ -1108,15 +1108,15 @@ function applySystemPromptMocks(input, promptMocks, callCounters) {
|
|
|
1108
1108
|
return input;
|
|
1109
1109
|
}
|
|
1110
1110
|
function resolveAIMock(modelName) {
|
|
1111
|
-
const
|
|
1112
|
-
const mocks =
|
|
1111
|
+
const g5 = globalThis;
|
|
1112
|
+
const mocks = g5["__ELASTICDASH_AI_MOCKS__"];
|
|
1113
1113
|
if (!mocks) return { mocked: false };
|
|
1114
1114
|
const entry = mocks[modelName];
|
|
1115
1115
|
if (!entry || entry.mode === "live") return { mocked: false };
|
|
1116
|
-
if (!
|
|
1117
|
-
|
|
1116
|
+
if (!g5["__ELASTICDASH_AI_CALL_COUNTERS__"]) {
|
|
1117
|
+
g5["__ELASTICDASH_AI_CALL_COUNTERS__"] = {};
|
|
1118
1118
|
}
|
|
1119
|
-
const counters =
|
|
1119
|
+
const counters = g5["__ELASTICDASH_AI_CALL_COUNTERS__"];
|
|
1120
1120
|
counters[modelName] = (counters[modelName] ?? 0) + 1;
|
|
1121
1121
|
const callNumber = counters[modelName];
|
|
1122
1122
|
if (entry.mode === "mock-all") {
|
|
@@ -1475,13 +1475,354 @@ var init_http = __esm({
|
|
|
1475
1475
|
}
|
|
1476
1476
|
});
|
|
1477
1477
|
|
|
1478
|
+
// src/interceptors/workflow-ai.ts
|
|
1479
|
+
function isAIWrapperActive() {
|
|
1480
|
+
return g3[AI_WRAPPER_KEY] > 0;
|
|
1481
|
+
}
|
|
1482
|
+
function enterAIWrapper() {
|
|
1483
|
+
g3[AI_WRAPPER_KEY] = (g3[AI_WRAPPER_KEY] ?? 0) + 1;
|
|
1484
|
+
}
|
|
1485
|
+
function leaveAIWrapper() {
|
|
1486
|
+
g3[AI_WRAPPER_KEY] = Math.max(0, (g3[AI_WRAPPER_KEY] ?? 0) - 1);
|
|
1487
|
+
}
|
|
1488
|
+
function extractUsage(output) {
|
|
1489
|
+
if (!output || typeof output !== "object") return void 0;
|
|
1490
|
+
const o = output;
|
|
1491
|
+
if (o.usage && typeof o.usage === "object") {
|
|
1492
|
+
const u = o.usage;
|
|
1493
|
+
if (u.input_tokens != null || u.output_tokens != null) {
|
|
1494
|
+
return {
|
|
1495
|
+
inputTokens: u.input_tokens,
|
|
1496
|
+
outputTokens: u.output_tokens,
|
|
1497
|
+
totalTokens: (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
if (u.prompt_tokens != null || u.completion_tokens != null) {
|
|
1501
|
+
return {
|
|
1502
|
+
inputTokens: u.prompt_tokens,
|
|
1503
|
+
outputTokens: u.completion_tokens,
|
|
1504
|
+
totalTokens: u.total_tokens
|
|
1505
|
+
};
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
if (o.usageMetadata && typeof o.usageMetadata === "object") {
|
|
1509
|
+
const u = o.usageMetadata;
|
|
1510
|
+
return {
|
|
1511
|
+
inputTokens: u.promptTokenCount,
|
|
1512
|
+
outputTokens: u.candidatesTokenCount,
|
|
1513
|
+
totalTokens: u.totalTokenCount
|
|
1514
|
+
};
|
|
1515
|
+
}
|
|
1516
|
+
return void 0;
|
|
1517
|
+
}
|
|
1518
|
+
function isReadableStream(v) {
|
|
1519
|
+
return typeof v === "object" && v !== null && typeof v.getReader === "function" && typeof v.tee === "function";
|
|
1520
|
+
}
|
|
1521
|
+
function isAsyncIterable(v) {
|
|
1522
|
+
return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
|
|
1523
|
+
}
|
|
1524
|
+
async function bufferReadableStream(stream) {
|
|
1525
|
+
const decoder = new TextDecoder();
|
|
1526
|
+
const reader = stream.getReader();
|
|
1527
|
+
let raw = "";
|
|
1528
|
+
try {
|
|
1529
|
+
for (; ; ) {
|
|
1530
|
+
const { done, value } = await reader.read();
|
|
1531
|
+
if (done) break;
|
|
1532
|
+
raw += decoder.decode(value, { stream: true });
|
|
1533
|
+
}
|
|
1534
|
+
} finally {
|
|
1535
|
+
reader.releaseLock();
|
|
1536
|
+
}
|
|
1537
|
+
return raw;
|
|
1538
|
+
}
|
|
1539
|
+
function reconstructStream2(raw) {
|
|
1540
|
+
const encoder = new TextEncoder();
|
|
1541
|
+
return new ReadableStream({
|
|
1542
|
+
start(ctrl) {
|
|
1543
|
+
ctrl.enqueue(encoder.encode(raw));
|
|
1544
|
+
ctrl.close();
|
|
1545
|
+
}
|
|
1546
|
+
});
|
|
1547
|
+
}
|
|
1548
|
+
function wrapAsyncIterable(source, onComplete) {
|
|
1549
|
+
return {
|
|
1550
|
+
[Symbol.asyncIterator]() {
|
|
1551
|
+
const iter = source[Symbol.asyncIterator]();
|
|
1552
|
+
const collected = [];
|
|
1553
|
+
return {
|
|
1554
|
+
async next() {
|
|
1555
|
+
const result = await iter.next();
|
|
1556
|
+
if (!result.done) {
|
|
1557
|
+
collected.push(result.value);
|
|
1558
|
+
} else {
|
|
1559
|
+
onComplete(collected);
|
|
1560
|
+
}
|
|
1561
|
+
return result;
|
|
1562
|
+
},
|
|
1563
|
+
async return(value) {
|
|
1564
|
+
onComplete(collected);
|
|
1565
|
+
return iter.return ? iter.return(value) : { done: true, value: void 0 };
|
|
1566
|
+
}
|
|
1567
|
+
};
|
|
1568
|
+
}
|
|
1569
|
+
};
|
|
1570
|
+
}
|
|
1571
|
+
function wrapAI(modelName, callFn) {
|
|
1572
|
+
return async (...args) => {
|
|
1573
|
+
await tryAutoInitHttpContext();
|
|
1574
|
+
const ctx = getCaptureContext();
|
|
1575
|
+
const httpCtx = getHttpRunContext();
|
|
1576
|
+
const obsCtx = getObservabilityContext();
|
|
1577
|
+
if (!ctx && !httpCtx && !obsCtx) return callFn(...args);
|
|
1578
|
+
enterAIWrapper();
|
|
1579
|
+
try {
|
|
1580
|
+
const start = rawDateNow();
|
|
1581
|
+
if (!ctx && !httpCtx && obsCtx) {
|
|
1582
|
+
const id2 = obsCtx.nextId();
|
|
1583
|
+
const input2 = args.length === 1 ? args[0] : args;
|
|
1584
|
+
try {
|
|
1585
|
+
const output = await callFn(...args);
|
|
1586
|
+
if (isReadableStream(output)) {
|
|
1587
|
+
const [streamForCaller, streamForRecorder] = output.tee();
|
|
1588
|
+
bufferReadableStream(streamForRecorder).then((rawText) => {
|
|
1589
|
+
const durationMs2 = rawDateNow() - start;
|
|
1590
|
+
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
1591
|
+
}).catch(() => {
|
|
1592
|
+
const durationMs2 = rawDateNow() - start;
|
|
1593
|
+
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
1594
|
+
});
|
|
1595
|
+
return streamForCaller;
|
|
1596
|
+
}
|
|
1597
|
+
if (isAsyncIterable(output)) {
|
|
1598
|
+
return wrapAsyncIterable(output, (chunks) => {
|
|
1599
|
+
const durationMs2 = rawDateNow() - start;
|
|
1600
|
+
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
1601
|
+
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
1602
|
+
});
|
|
1603
|
+
}
|
|
1604
|
+
const durationMs = rawDateNow() - start;
|
|
1605
|
+
const usage = extractUsage(output);
|
|
1606
|
+
const event = {
|
|
1607
|
+
id: id2,
|
|
1608
|
+
type: "ai",
|
|
1609
|
+
name: modelName,
|
|
1610
|
+
input: input2,
|
|
1611
|
+
output,
|
|
1612
|
+
timestamp: start,
|
|
1613
|
+
durationMs,
|
|
1614
|
+
...usage ? { usage } : {}
|
|
1615
|
+
};
|
|
1616
|
+
pushTelemetryEvent(event);
|
|
1617
|
+
return output;
|
|
1618
|
+
} catch (e) {
|
|
1619
|
+
const durationMs = rawDateNow() - start;
|
|
1620
|
+
pushTelemetryEvent({
|
|
1621
|
+
id: id2,
|
|
1622
|
+
type: "ai",
|
|
1623
|
+
name: modelName,
|
|
1624
|
+
input: input2,
|
|
1625
|
+
output: { error: String(e) },
|
|
1626
|
+
timestamp: start,
|
|
1627
|
+
durationMs
|
|
1628
|
+
});
|
|
1629
|
+
throw e;
|
|
1630
|
+
}
|
|
1631
|
+
}
|
|
1632
|
+
if (ctx) {
|
|
1633
|
+
const { recorder, replay } = ctx;
|
|
1634
|
+
const id2 = recorder.nextId();
|
|
1635
|
+
if (replay.shouldReplay(id2)) {
|
|
1636
|
+
const historical = replay.getRecordedEvent(id2);
|
|
1637
|
+
if (historical?.streamed === true) {
|
|
1638
|
+
const raw = typeof historical.streamRaw === "string" ? historical.streamRaw : "";
|
|
1639
|
+
return reconstructStream2(raw);
|
|
1640
|
+
}
|
|
1641
|
+
return replay.getRecordedResult(id2);
|
|
1642
|
+
}
|
|
1643
|
+
const aiMock2 = resolveAIMock(modelName);
|
|
1644
|
+
if (aiMock2.mocked) {
|
|
1645
|
+
const input3 = args.length === 1 ? args[0] : args;
|
|
1646
|
+
const event = {
|
|
1647
|
+
id: id2,
|
|
1648
|
+
type: "ai",
|
|
1649
|
+
name: modelName,
|
|
1650
|
+
input: input3,
|
|
1651
|
+
output: aiMock2.result,
|
|
1652
|
+
timestamp: start,
|
|
1653
|
+
durationMs: 0
|
|
1654
|
+
};
|
|
1655
|
+
recorder.record(event);
|
|
1656
|
+
if (httpCtx) pushTelemetryEvent(event);
|
|
1657
|
+
return aiMock2.result;
|
|
1658
|
+
}
|
|
1659
|
+
const rawInput = args.length === 1 ? args[0] : args;
|
|
1660
|
+
const promptModifiedInput = resolvePromptMock(rawInput);
|
|
1661
|
+
const userPromptModifiedInput = resolveUserPromptMock(promptModifiedInput !== void 0 ? promptModifiedInput : rawInput);
|
|
1662
|
+
const modifiedInput = userPromptModifiedInput !== void 0 ? userPromptModifiedInput : promptModifiedInput;
|
|
1663
|
+
const effectiveArgs = modifiedInput !== void 0 ? [modifiedInput] : args;
|
|
1664
|
+
const input2 = modifiedInput !== void 0 ? modifiedInput : rawInput;
|
|
1665
|
+
try {
|
|
1666
|
+
const output = await callFn(...effectiveArgs);
|
|
1667
|
+
if (isReadableStream(output)) {
|
|
1668
|
+
const [streamForCaller, streamForRecorder] = output.tee();
|
|
1669
|
+
bufferReadableStream(streamForRecorder).then((rawText) => {
|
|
1670
|
+
const durationMs2 = rawDateNow() - start;
|
|
1671
|
+
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
1672
|
+
recorder.record(event2);
|
|
1673
|
+
if (httpCtx) pushTelemetryEvent(event2);
|
|
1674
|
+
}).catch(() => {
|
|
1675
|
+
const durationMs2 = rawDateNow() - start;
|
|
1676
|
+
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 };
|
|
1677
|
+
recorder.record(event2);
|
|
1678
|
+
if (httpCtx) pushTelemetryEvent(event2);
|
|
1679
|
+
});
|
|
1680
|
+
return streamForCaller;
|
|
1681
|
+
}
|
|
1682
|
+
if (isAsyncIterable(output)) {
|
|
1683
|
+
return wrapAsyncIterable(output, (chunks) => {
|
|
1684
|
+
const durationMs2 = rawDateNow() - start;
|
|
1685
|
+
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
1686
|
+
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
1687
|
+
recorder.record(event2);
|
|
1688
|
+
if (httpCtx) pushTelemetryEvent(event2);
|
|
1689
|
+
});
|
|
1690
|
+
}
|
|
1691
|
+
const durationMs = rawDateNow() - start;
|
|
1692
|
+
const usage = extractUsage(output);
|
|
1693
|
+
const event = {
|
|
1694
|
+
id: id2,
|
|
1695
|
+
type: "ai",
|
|
1696
|
+
name: modelName,
|
|
1697
|
+
input: input2,
|
|
1698
|
+
output,
|
|
1699
|
+
timestamp: start,
|
|
1700
|
+
durationMs,
|
|
1701
|
+
...usage ? { usage } : {}
|
|
1702
|
+
};
|
|
1703
|
+
recorder.record(event);
|
|
1704
|
+
if (httpCtx) pushTelemetryEvent(event);
|
|
1705
|
+
return output;
|
|
1706
|
+
} catch (e) {
|
|
1707
|
+
const durationMs = rawDateNow() - start;
|
|
1708
|
+
const event = {
|
|
1709
|
+
id: id2,
|
|
1710
|
+
type: "ai",
|
|
1711
|
+
name: modelName,
|
|
1712
|
+
input: input2,
|
|
1713
|
+
output: { error: String(e) },
|
|
1714
|
+
timestamp: start,
|
|
1715
|
+
durationMs
|
|
1716
|
+
};
|
|
1717
|
+
recorder.record(event);
|
|
1718
|
+
if (httpCtx) pushTelemetryEvent(event);
|
|
1719
|
+
throw e;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
const id = httpCtx.nextId();
|
|
1723
|
+
const frozen = getHttpFrozenEvent(id);
|
|
1724
|
+
if (frozen) {
|
|
1725
|
+
pushTelemetryEvent(frozen);
|
|
1726
|
+
if (frozen.streamed === true) {
|
|
1727
|
+
const raw = typeof frozen.streamRaw === "string" ? frozen.streamRaw : "";
|
|
1728
|
+
return reconstructStream2(raw);
|
|
1729
|
+
}
|
|
1730
|
+
return frozen.output;
|
|
1731
|
+
}
|
|
1732
|
+
const aiMock = getHttpAIMock(modelName);
|
|
1733
|
+
if (aiMock.mocked) {
|
|
1734
|
+
const input2 = args.length === 1 ? args[0] : args;
|
|
1735
|
+
const event = {
|
|
1736
|
+
id,
|
|
1737
|
+
type: "ai",
|
|
1738
|
+
name: modelName,
|
|
1739
|
+
input: input2,
|
|
1740
|
+
output: aiMock.result,
|
|
1741
|
+
timestamp: start,
|
|
1742
|
+
durationMs: 0
|
|
1743
|
+
};
|
|
1744
|
+
pushTelemetryEvent(event);
|
|
1745
|
+
return aiMock.result;
|
|
1746
|
+
}
|
|
1747
|
+
const rawHttpInput = args.length === 1 ? args[0] : args;
|
|
1748
|
+
const httpSystemModified = getHttpPromptMock(rawHttpInput);
|
|
1749
|
+
const httpUserModified = getHttpUserPromptMock(httpSystemModified !== void 0 ? httpSystemModified : rawHttpInput);
|
|
1750
|
+
const httpModifiedInput = httpUserModified !== void 0 ? httpUserModified : httpSystemModified;
|
|
1751
|
+
const httpEffectiveArgs = httpModifiedInput !== void 0 ? [httpModifiedInput] : args;
|
|
1752
|
+
const input = httpModifiedInput !== void 0 ? httpModifiedInput : rawHttpInput;
|
|
1753
|
+
try {
|
|
1754
|
+
const output = await callFn(...httpEffectiveArgs);
|
|
1755
|
+
if (isReadableStream(output)) {
|
|
1756
|
+
const [streamForCaller, streamForRecorder] = output.tee();
|
|
1757
|
+
bufferReadableStream(streamForRecorder).then((rawText) => {
|
|
1758
|
+
const durationMs2 = rawDateNow() - start;
|
|
1759
|
+
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
1760
|
+
}).catch(() => {
|
|
1761
|
+
const durationMs2 = rawDateNow() - start;
|
|
1762
|
+
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
1763
|
+
});
|
|
1764
|
+
return streamForCaller;
|
|
1765
|
+
}
|
|
1766
|
+
if (isAsyncIterable(output)) {
|
|
1767
|
+
return wrapAsyncIterable(output, (chunks) => {
|
|
1768
|
+
const durationMs2 = rawDateNow() - start;
|
|
1769
|
+
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
1770
|
+
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
const durationMs = rawDateNow() - start;
|
|
1774
|
+
const usage = extractUsage(output);
|
|
1775
|
+
const event = {
|
|
1776
|
+
id,
|
|
1777
|
+
type: "ai",
|
|
1778
|
+
name: modelName,
|
|
1779
|
+
input,
|
|
1780
|
+
output,
|
|
1781
|
+
timestamp: start,
|
|
1782
|
+
durationMs,
|
|
1783
|
+
...usage ? { usage } : {}
|
|
1784
|
+
};
|
|
1785
|
+
pushTelemetryEvent(event);
|
|
1786
|
+
return output;
|
|
1787
|
+
} catch (e) {
|
|
1788
|
+
const durationMs = rawDateNow() - start;
|
|
1789
|
+
pushTelemetryEvent({
|
|
1790
|
+
id,
|
|
1791
|
+
type: "ai",
|
|
1792
|
+
name: modelName,
|
|
1793
|
+
input,
|
|
1794
|
+
output: { error: String(e) },
|
|
1795
|
+
timestamp: start,
|
|
1796
|
+
durationMs
|
|
1797
|
+
});
|
|
1798
|
+
throw e;
|
|
1799
|
+
}
|
|
1800
|
+
} finally {
|
|
1801
|
+
leaveAIWrapper();
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
}
|
|
1805
|
+
var AI_WRAPPER_KEY, g3;
|
|
1806
|
+
var init_workflow_ai = __esm({
|
|
1807
|
+
"src/interceptors/workflow-ai.ts"() {
|
|
1808
|
+
"use strict";
|
|
1809
|
+
init_recorder();
|
|
1810
|
+
init_side_effects();
|
|
1811
|
+
init_telemetry_push();
|
|
1812
|
+
init_mock_resolver();
|
|
1813
|
+
AI_WRAPPER_KEY = "__elasticdash_ai_wrapper_depth__";
|
|
1814
|
+
g3 = globalThis;
|
|
1815
|
+
if (g3[AI_WRAPPER_KEY] == null) g3[AI_WRAPPER_KEY] = 0;
|
|
1816
|
+
}
|
|
1817
|
+
});
|
|
1818
|
+
|
|
1478
1819
|
// src/interceptors/ai-interceptor.ts
|
|
1479
1820
|
var ai_interceptor_exports = {};
|
|
1480
1821
|
__export(ai_interceptor_exports, {
|
|
1481
1822
|
installAIInterceptor: () => installAIInterceptor,
|
|
1482
1823
|
uninstallAIInterceptor: () => uninstallAIInterceptor
|
|
1483
1824
|
});
|
|
1484
|
-
function
|
|
1825
|
+
function extractUsage2(provider, body) {
|
|
1485
1826
|
if (provider === "openai" || provider === "grok" || provider === "kimi") {
|
|
1486
1827
|
const u = body.usage;
|
|
1487
1828
|
if (!u) return void 0;
|
|
@@ -1799,6 +2140,9 @@ function installAIInterceptor() {
|
|
|
1799
2140
|
globalThis.fetch = async function patchedFetch(input, init) {
|
|
1800
2141
|
const url = typeof input === "string" ? input : input instanceof URL ? input.href : input.url;
|
|
1801
2142
|
const provider = detectProvider2(url);
|
|
2143
|
+
if (provider && isAIWrapperActive()) {
|
|
2144
|
+
return originalFetch2(input, init);
|
|
2145
|
+
}
|
|
1802
2146
|
const traceAtCall = getCurrentTrace();
|
|
1803
2147
|
const obsCtx = getObservabilityContext();
|
|
1804
2148
|
const httpCtx = getHttpRunContext();
|
|
@@ -1842,7 +2186,7 @@ function installAIInterceptor() {
|
|
|
1842
2186
|
const cloned = response2.clone();
|
|
1843
2187
|
const responseBody = await cloned.json();
|
|
1844
2188
|
const completion = extractCompletion2(provider, responseBody);
|
|
1845
|
-
const usage =
|
|
2189
|
+
const usage = extractUsage2(provider, responseBody);
|
|
1846
2190
|
const durationMs = rawDateNow() - start;
|
|
1847
2191
|
const event = {
|
|
1848
2192
|
id,
|
|
@@ -1898,7 +2242,7 @@ function installAIInterceptor() {
|
|
|
1898
2242
|
const cloned = response2.clone();
|
|
1899
2243
|
const responseBody = await cloned.json();
|
|
1900
2244
|
const completion = extractCompletion2(provider, responseBody);
|
|
1901
|
-
const usage =
|
|
2245
|
+
const usage = extractUsage2(provider, responseBody);
|
|
1902
2246
|
const durationMs = rawDateNow() - start;
|
|
1903
2247
|
pushTelemetryEvent({ id, type: "ai", name: model, input: eventInput, output: { completion }, timestamp: start, durationMs, ...usage ? { usage } : {} });
|
|
1904
2248
|
} catch {
|
|
@@ -1970,7 +2314,7 @@ function installAIInterceptor() {
|
|
|
1970
2314
|
const cloned = response2.clone();
|
|
1971
2315
|
const responseBody = await cloned.json();
|
|
1972
2316
|
const completion = extractCompletion2(provider, responseBody);
|
|
1973
|
-
const usage =
|
|
2317
|
+
const usage = extractUsage2(provider, responseBody);
|
|
1974
2318
|
const assistantMessage = extractAssistantMessage(provider, responseBody);
|
|
1975
2319
|
traceAtCall.recordLLMStep({ model, provider, prompt, completion, workflowEventId: id, durationMs });
|
|
1976
2320
|
recorder.record({ id, type: "ai", name: model, input: { url, provider, model, prompt, messages }, output: assistantMessage ?? responseBody, timestamp: start, durationMs, usage });
|
|
@@ -2018,6 +2362,7 @@ var init_ai_interceptor = __esm({
|
|
|
2018
2362
|
init_recorder();
|
|
2019
2363
|
init_side_effects();
|
|
2020
2364
|
init_telemetry_push();
|
|
2365
|
+
init_workflow_ai();
|
|
2021
2366
|
AI_PATTERNS2 = {
|
|
2022
2367
|
openai: /https?:\/\/api\.openai\.com\/v1\/((chat\/)?completions|embeddings)/,
|
|
2023
2368
|
anthropic: /https?:\/\/api\.anthropic\.com\/v1\/messages/,
|
|
@@ -3294,14 +3639,14 @@ var init_observability = __esm({
|
|
|
3294
3639
|
// src/interceptors/telemetry-push.ts
|
|
3295
3640
|
function setObservabilityContext(ctx) {
|
|
3296
3641
|
obsAls.enterWith(ctx);
|
|
3297
|
-
|
|
3642
|
+
g4[GLOBAL_OBS_KEY] = ctx;
|
|
3298
3643
|
}
|
|
3299
3644
|
function getObservabilityContext() {
|
|
3300
|
-
return obsAls.getStore() ??
|
|
3645
|
+
return obsAls.getStore() ?? g4[GLOBAL_OBS_KEY];
|
|
3301
3646
|
}
|
|
3302
3647
|
function clearObservabilityContext() {
|
|
3303
3648
|
obsAls.enterWith(void 0);
|
|
3304
|
-
|
|
3649
|
+
g4[GLOBAL_OBS_KEY] = void 0;
|
|
3305
3650
|
}
|
|
3306
3651
|
function buildContext(runId, dashboardUrl, frozenEvents, promptMocksRecord = {}, toolMockConfig, aiMockConfig, userPromptMocks) {
|
|
3307
3652
|
let counter = 0;
|
|
@@ -3323,15 +3668,15 @@ function buildContext(runId, dashboardUrl, frozenEvents, promptMocksRecord = {},
|
|
|
3323
3668
|
};
|
|
3324
3669
|
}
|
|
3325
3670
|
function setGlobalHttpContext(ctx) {
|
|
3326
|
-
|
|
3671
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3327
3672
|
}
|
|
3328
3673
|
function clearGlobalHttpContext() {
|
|
3329
|
-
|
|
3674
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3330
3675
|
}
|
|
3331
3676
|
function setHttpRunContext(runId, dashboardUrl) {
|
|
3332
3677
|
const ctx = buildContext(runId, dashboardUrl, [], {});
|
|
3333
3678
|
httpRunAls.enterWith(ctx);
|
|
3334
|
-
|
|
3679
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3335
3680
|
ensureInterceptorsInstalled().catch(() => {
|
|
3336
3681
|
});
|
|
3337
3682
|
}
|
|
@@ -3361,11 +3706,11 @@ async function initHttpRunContext(runId, dashboardUrl) {
|
|
|
3361
3706
|
}
|
|
3362
3707
|
const ctx = buildContext(runId, dashboardUrl, frozenEvents, promptMocks, toolMockConfig, aiMockConfig, userPromptMocks);
|
|
3363
3708
|
httpRunAls.enterWith(ctx);
|
|
3364
|
-
|
|
3709
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3365
3710
|
await ensureInterceptorsInstalled();
|
|
3366
3711
|
}
|
|
3367
3712
|
function getHttpRunContext() {
|
|
3368
|
-
return httpRunAls.getStore() ??
|
|
3713
|
+
return httpRunAls.getStore() ?? g4[GLOBAL_CTX_KEY];
|
|
3369
3714
|
}
|
|
3370
3715
|
function getHttpFrozenEvent(id) {
|
|
3371
3716
|
return getHttpRunContext()?.frozenEvents.get(id);
|
|
@@ -3497,8 +3842,8 @@ function pushTelemetryEvent(event, explicitCtx) {
|
|
|
3497
3842
|
});
|
|
3498
3843
|
}
|
|
3499
3844
|
async function ensureInterceptorsInstalled() {
|
|
3500
|
-
if (
|
|
3501
|
-
|
|
3845
|
+
if (g4[INTERCEPTORS_KEY]) return;
|
|
3846
|
+
g4[INTERCEPTORS_KEY] = true;
|
|
3502
3847
|
try {
|
|
3503
3848
|
const [httpMod, aiMod, dbMod] = await Promise.all([
|
|
3504
3849
|
Promise.resolve().then(() => (init_http(), http_exports)),
|
|
@@ -3514,11 +3859,11 @@ async function ensureInterceptorsInstalled() {
|
|
|
3514
3859
|
async function runInHttpContext(runId, dashboardUrl, callback) {
|
|
3515
3860
|
await ensureInterceptorsInstalled();
|
|
3516
3861
|
const ctx = buildContext(runId, dashboardUrl, [], {});
|
|
3517
|
-
|
|
3862
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3518
3863
|
try {
|
|
3519
3864
|
return await httpRunAls.run(ctx, callback);
|
|
3520
3865
|
} finally {
|
|
3521
|
-
|
|
3866
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3522
3867
|
}
|
|
3523
3868
|
}
|
|
3524
3869
|
async function runWithInitializedHttpContext(runId, dashboardUrl, callback) {
|
|
@@ -3555,11 +3900,11 @@ async function runWithInitializedHttpContext(runId, dashboardUrl, callback) {
|
|
|
3555
3900
|
}
|
|
3556
3901
|
await ensureInterceptorsInstalled();
|
|
3557
3902
|
const ctx = buildContext(runId, dashboardUrl, frozenEvents, promptMocks, toolMockConfig, aiMockConfig, userPromptMocks);
|
|
3558
|
-
|
|
3903
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3559
3904
|
try {
|
|
3560
3905
|
return await httpRunAls.run(ctx, callback);
|
|
3561
3906
|
} finally {
|
|
3562
|
-
|
|
3907
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3563
3908
|
}
|
|
3564
3909
|
}
|
|
3565
3910
|
async function tryAutoInitHttpContext() {
|
|
@@ -3568,8 +3913,8 @@ async function tryAutoInitHttpContext() {
|
|
|
3568
3913
|
const apiUrl = (typeof process !== "undefined" && process.env?.ELASTICDASH_API_URL) ?? "";
|
|
3569
3914
|
if (apiUrl) {
|
|
3570
3915
|
const obsInitKey = "__elasticdash_obs_auto_init__";
|
|
3571
|
-
if (!
|
|
3572
|
-
|
|
3916
|
+
if (!g4[obsInitKey]) {
|
|
3917
|
+
g4[obsInitKey] = (async () => {
|
|
3573
3918
|
try {
|
|
3574
3919
|
const { initObservability: initObservability2 } = await Promise.resolve().then(() => (init_observability(), observability_exports));
|
|
3575
3920
|
initObservability2({
|
|
@@ -3582,13 +3927,13 @@ async function tryAutoInitHttpContext() {
|
|
|
3582
3927
|
}
|
|
3583
3928
|
})();
|
|
3584
3929
|
}
|
|
3585
|
-
await
|
|
3930
|
+
await g4[obsInitKey];
|
|
3586
3931
|
return;
|
|
3587
3932
|
}
|
|
3588
3933
|
const serverUrl = (typeof process !== "undefined" && process.env?.ELASTICDASH_SERVER) ?? "";
|
|
3589
3934
|
if (!serverUrl) return;
|
|
3590
|
-
if (!
|
|
3591
|
-
|
|
3935
|
+
if (!g4[AUTO_INIT_KEY]) {
|
|
3936
|
+
g4[AUTO_INIT_KEY] = (async () => {
|
|
3592
3937
|
try {
|
|
3593
3938
|
const runId = (typeof process !== "undefined" && process.env?.ELASTICDASH_RUN_ID) ?? "";
|
|
3594
3939
|
if (runId) {
|
|
@@ -3600,9 +3945,9 @@ async function tryAutoInitHttpContext() {
|
|
|
3600
3945
|
}
|
|
3601
3946
|
})();
|
|
3602
3947
|
}
|
|
3603
|
-
await
|
|
3948
|
+
await g4[AUTO_INIT_KEY];
|
|
3604
3949
|
}
|
|
3605
|
-
var import_node_async_hooks3, import_node_crypto4,
|
|
3950
|
+
var import_node_async_hooks3, import_node_crypto4, g4, HTTP_RUN_ALS_KEY, GLOBAL_CTX_KEY, OBS_ALS_KEY, GLOBAL_OBS_KEY, httpRunAls, obsAls, INTERCEPTORS_KEY, AUTO_INIT_KEY;
|
|
3606
3951
|
var init_telemetry_push = __esm({
|
|
3607
3952
|
"src/interceptors/telemetry-push.ts"() {
|
|
3608
3953
|
"use strict";
|
|
@@ -3610,15 +3955,15 @@ var init_telemetry_push = __esm({
|
|
|
3610
3955
|
import_node_crypto4 = require("node:crypto");
|
|
3611
3956
|
init_mock_resolver();
|
|
3612
3957
|
init_debug();
|
|
3613
|
-
|
|
3958
|
+
g4 = globalThis;
|
|
3614
3959
|
HTTP_RUN_ALS_KEY = "__elasticdash_http_run_als__";
|
|
3615
3960
|
GLOBAL_CTX_KEY = "__elasticdash_global_http_ctx__";
|
|
3616
3961
|
OBS_ALS_KEY = "__elasticdash_obs_als__";
|
|
3617
3962
|
GLOBAL_OBS_KEY = "__elasticdash_global_obs_ctx__";
|
|
3618
|
-
httpRunAls =
|
|
3619
|
-
if (!
|
|
3620
|
-
obsAls =
|
|
3621
|
-
if (!
|
|
3963
|
+
httpRunAls = g4[HTTP_RUN_ALS_KEY] ?? new import_node_async_hooks3.AsyncLocalStorage();
|
|
3964
|
+
if (!g4[HTTP_RUN_ALS_KEY]) g4[HTTP_RUN_ALS_KEY] = httpRunAls;
|
|
3965
|
+
obsAls = g4[OBS_ALS_KEY] ?? new import_node_async_hooks3.AsyncLocalStorage();
|
|
3966
|
+
if (!g4[OBS_ALS_KEY]) g4[OBS_ALS_KEY] = obsAls;
|
|
3622
3967
|
INTERCEPTORS_KEY = "__elasticdash_interceptors_installed__";
|
|
3623
3968
|
AUTO_INIT_KEY = "__elasticdash_auto_init_promise__";
|
|
3624
3969
|
}
|
|
@@ -4315,13 +4660,13 @@ function toTraceArgs2(input) {
|
|
|
4315
4660
|
if (input === void 0) return void 0;
|
|
4316
4661
|
return { value: input };
|
|
4317
4662
|
}
|
|
4318
|
-
function
|
|
4663
|
+
function isReadableStream2(v) {
|
|
4319
4664
|
return typeof v === "object" && v !== null && typeof v.getReader === "function" && typeof v.tee === "function";
|
|
4320
4665
|
}
|
|
4321
|
-
function
|
|
4666
|
+
function isAsyncIterable2(v) {
|
|
4322
4667
|
return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
|
|
4323
4668
|
}
|
|
4324
|
-
async function
|
|
4669
|
+
async function bufferReadableStream2(stream) {
|
|
4325
4670
|
const decoder = new TextDecoder();
|
|
4326
4671
|
const reader = stream.getReader();
|
|
4327
4672
|
let raw = "";
|
|
@@ -4336,7 +4681,7 @@ async function bufferReadableStream(stream) {
|
|
|
4336
4681
|
}
|
|
4337
4682
|
return raw;
|
|
4338
4683
|
}
|
|
4339
|
-
function
|
|
4684
|
+
function reconstructStream3(raw) {
|
|
4340
4685
|
const encoder = new TextEncoder();
|
|
4341
4686
|
return new ReadableStream({
|
|
4342
4687
|
start(ctrl) {
|
|
@@ -4345,7 +4690,7 @@ function reconstructStream2(raw) {
|
|
|
4345
4690
|
}
|
|
4346
4691
|
});
|
|
4347
4692
|
}
|
|
4348
|
-
function
|
|
4693
|
+
function wrapAsyncIterable2(source, onComplete) {
|
|
4349
4694
|
return {
|
|
4350
4695
|
[Symbol.asyncIterator]() {
|
|
4351
4696
|
const iter = source[Symbol.asyncIterator]();
|
|
@@ -4385,9 +4730,9 @@ function wrapTool(name, fn) {
|
|
|
4385
4730
|
try {
|
|
4386
4731
|
const output = await fn(...args);
|
|
4387
4732
|
const durationMs = rawDateNow() - start2;
|
|
4388
|
-
if (
|
|
4733
|
+
if (isReadableStream2(output)) {
|
|
4389
4734
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4390
|
-
|
|
4735
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4391
4736
|
const durationMs2 = rawDateNow() - start2;
|
|
4392
4737
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
4393
4738
|
}).catch(() => {
|
|
@@ -4396,8 +4741,8 @@ function wrapTool(name, fn) {
|
|
|
4396
4741
|
});
|
|
4397
4742
|
return streamForCaller;
|
|
4398
4743
|
}
|
|
4399
|
-
if (
|
|
4400
|
-
return
|
|
4744
|
+
if (isAsyncIterable2(output)) {
|
|
4745
|
+
return wrapAsyncIterable2(output, (chunks) => {
|
|
4401
4746
|
const durationMs2 = rawDateNow() - start2;
|
|
4402
4747
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4403
4748
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
@@ -4419,7 +4764,7 @@ function wrapTool(name, fn) {
|
|
|
4419
4764
|
pushTelemetryEvent(frozen);
|
|
4420
4765
|
if (frozen.streamed === true) {
|
|
4421
4766
|
const raw = typeof frozen.streamRaw === "string" ? frozen.streamRaw : "";
|
|
4422
|
-
return
|
|
4767
|
+
return reconstructStream3(raw);
|
|
4423
4768
|
}
|
|
4424
4769
|
return frozen.output;
|
|
4425
4770
|
}
|
|
@@ -4432,9 +4777,9 @@ function wrapTool(name, fn) {
|
|
|
4432
4777
|
const start2 = rawDateNow();
|
|
4433
4778
|
try {
|
|
4434
4779
|
const output = await fn(...args);
|
|
4435
|
-
if (
|
|
4780
|
+
if (isReadableStream2(output)) {
|
|
4436
4781
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4437
|
-
|
|
4782
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4438
4783
|
const durationMs2 = rawDateNow() - start2;
|
|
4439
4784
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
4440
4785
|
}).catch(() => {
|
|
@@ -4443,8 +4788,8 @@ function wrapTool(name, fn) {
|
|
|
4443
4788
|
});
|
|
4444
4789
|
return streamForCaller;
|
|
4445
4790
|
}
|
|
4446
|
-
if (
|
|
4447
|
-
return
|
|
4791
|
+
if (isAsyncIterable2(output)) {
|
|
4792
|
+
return wrapAsyncIterable2(output, (chunks) => {
|
|
4448
4793
|
const durationMs2 = rawDateNow() - start2;
|
|
4449
4794
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4450
4795
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
@@ -4468,7 +4813,7 @@ function wrapTool(name, fn) {
|
|
|
4468
4813
|
if (historical) recorder.record(historical);
|
|
4469
4814
|
if (historical?.streamed === true) {
|
|
4470
4815
|
const raw = typeof historical.streamRaw === "string" ? historical.streamRaw : "";
|
|
4471
|
-
const stream =
|
|
4816
|
+
const stream = reconstructStream3(raw);
|
|
4472
4817
|
if (trace && typeof trace.recordToolCall === "function") {
|
|
4473
4818
|
trace.recordToolCall({ name, args: toTraceArgs2(input), result: stream, workflowEventId: id });
|
|
4474
4819
|
}
|
|
@@ -4480,15 +4825,15 @@ function wrapTool(name, fn) {
|
|
|
4480
4825
|
}
|
|
4481
4826
|
return replayed;
|
|
4482
4827
|
}
|
|
4483
|
-
const
|
|
4484
|
-
const prev =
|
|
4485
|
-
|
|
4828
|
+
const g5 = globalThis;
|
|
4829
|
+
const prev = g5[TOOL_WRAPPER_ACTIVE_KEY];
|
|
4830
|
+
g5[TOOL_WRAPPER_ACTIVE_KEY] = true;
|
|
4486
4831
|
const start = rawDateNow();
|
|
4487
4832
|
try {
|
|
4488
4833
|
const output = await fn(...args);
|
|
4489
|
-
if (
|
|
4834
|
+
if (isReadableStream2(output)) {
|
|
4490
4835
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4491
|
-
|
|
4836
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4492
4837
|
const durationMs2 = rawDateNow() - start;
|
|
4493
4838
|
const event = { id, type: "tool", name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4494
4839
|
recorder.record(event);
|
|
@@ -4505,8 +4850,8 @@ function wrapTool(name, fn) {
|
|
|
4505
4850
|
}
|
|
4506
4851
|
return result;
|
|
4507
4852
|
}
|
|
4508
|
-
if (
|
|
4509
|
-
const wrapped =
|
|
4853
|
+
if (isAsyncIterable2(output)) {
|
|
4854
|
+
const wrapped = wrapAsyncIterable2(output, (chunks) => {
|
|
4510
4855
|
const durationMs2 = rawDateNow() - start;
|
|
4511
4856
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4512
4857
|
const event = { id, type: "tool", name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
@@ -4536,331 +4881,14 @@ function wrapTool(name, fn) {
|
|
|
4536
4881
|
}
|
|
4537
4882
|
throw e;
|
|
4538
4883
|
} finally {
|
|
4539
|
-
if (prev === void 0) delete
|
|
4540
|
-
else
|
|
4541
|
-
}
|
|
4542
|
-
};
|
|
4543
|
-
}
|
|
4544
|
-
|
|
4545
|
-
// src/interceptors/workflow-ai.ts
|
|
4546
|
-
init_recorder();
|
|
4547
|
-
init_side_effects();
|
|
4548
|
-
init_telemetry_push();
|
|
4549
|
-
init_mock_resolver();
|
|
4550
|
-
function extractUsage2(output) {
|
|
4551
|
-
if (!output || typeof output !== "object") return void 0;
|
|
4552
|
-
const o = output;
|
|
4553
|
-
if (o.usage && typeof o.usage === "object") {
|
|
4554
|
-
const u = o.usage;
|
|
4555
|
-
if (u.input_tokens != null || u.output_tokens != null) {
|
|
4556
|
-
return {
|
|
4557
|
-
inputTokens: u.input_tokens,
|
|
4558
|
-
outputTokens: u.output_tokens,
|
|
4559
|
-
totalTokens: (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
|
|
4560
|
-
};
|
|
4561
|
-
}
|
|
4562
|
-
if (u.prompt_tokens != null || u.completion_tokens != null) {
|
|
4563
|
-
return {
|
|
4564
|
-
inputTokens: u.prompt_tokens,
|
|
4565
|
-
outputTokens: u.completion_tokens,
|
|
4566
|
-
totalTokens: u.total_tokens
|
|
4567
|
-
};
|
|
4568
|
-
}
|
|
4569
|
-
}
|
|
4570
|
-
if (o.usageMetadata && typeof o.usageMetadata === "object") {
|
|
4571
|
-
const u = o.usageMetadata;
|
|
4572
|
-
return {
|
|
4573
|
-
inputTokens: u.promptTokenCount,
|
|
4574
|
-
outputTokens: u.candidatesTokenCount,
|
|
4575
|
-
totalTokens: u.totalTokenCount
|
|
4576
|
-
};
|
|
4577
|
-
}
|
|
4578
|
-
return void 0;
|
|
4579
|
-
}
|
|
4580
|
-
function isReadableStream2(v) {
|
|
4581
|
-
return typeof v === "object" && v !== null && typeof v.getReader === "function" && typeof v.tee === "function";
|
|
4582
|
-
}
|
|
4583
|
-
function isAsyncIterable2(v) {
|
|
4584
|
-
return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
|
|
4585
|
-
}
|
|
4586
|
-
async function bufferReadableStream2(stream) {
|
|
4587
|
-
const decoder = new TextDecoder();
|
|
4588
|
-
const reader = stream.getReader();
|
|
4589
|
-
let raw = "";
|
|
4590
|
-
try {
|
|
4591
|
-
for (; ; ) {
|
|
4592
|
-
const { done, value } = await reader.read();
|
|
4593
|
-
if (done) break;
|
|
4594
|
-
raw += decoder.decode(value, { stream: true });
|
|
4595
|
-
}
|
|
4596
|
-
} finally {
|
|
4597
|
-
reader.releaseLock();
|
|
4598
|
-
}
|
|
4599
|
-
return raw;
|
|
4600
|
-
}
|
|
4601
|
-
function reconstructStream3(raw) {
|
|
4602
|
-
const encoder = new TextEncoder();
|
|
4603
|
-
return new ReadableStream({
|
|
4604
|
-
start(ctrl) {
|
|
4605
|
-
ctrl.enqueue(encoder.encode(raw));
|
|
4606
|
-
ctrl.close();
|
|
4607
|
-
}
|
|
4608
|
-
});
|
|
4609
|
-
}
|
|
4610
|
-
function wrapAsyncIterable2(source, onComplete) {
|
|
4611
|
-
return {
|
|
4612
|
-
[Symbol.asyncIterator]() {
|
|
4613
|
-
const iter = source[Symbol.asyncIterator]();
|
|
4614
|
-
const collected = [];
|
|
4615
|
-
return {
|
|
4616
|
-
async next() {
|
|
4617
|
-
const result = await iter.next();
|
|
4618
|
-
if (!result.done) {
|
|
4619
|
-
collected.push(result.value);
|
|
4620
|
-
} else {
|
|
4621
|
-
onComplete(collected);
|
|
4622
|
-
}
|
|
4623
|
-
return result;
|
|
4624
|
-
},
|
|
4625
|
-
async return(value) {
|
|
4626
|
-
onComplete(collected);
|
|
4627
|
-
return iter.return ? iter.return(value) : { done: true, value: void 0 };
|
|
4628
|
-
}
|
|
4629
|
-
};
|
|
4630
|
-
}
|
|
4631
|
-
};
|
|
4632
|
-
}
|
|
4633
|
-
function wrapAI(modelName, callFn) {
|
|
4634
|
-
return async (...args) => {
|
|
4635
|
-
await tryAutoInitHttpContext();
|
|
4636
|
-
const ctx = getCaptureContext();
|
|
4637
|
-
const httpCtx = getHttpRunContext();
|
|
4638
|
-
const obsCtx = getObservabilityContext();
|
|
4639
|
-
if (!ctx && !httpCtx && !obsCtx) return callFn(...args);
|
|
4640
|
-
const start = rawDateNow();
|
|
4641
|
-
if (!ctx && !httpCtx && obsCtx) {
|
|
4642
|
-
const id2 = obsCtx.nextId();
|
|
4643
|
-
const input2 = args.length === 1 ? args[0] : args;
|
|
4644
|
-
try {
|
|
4645
|
-
const output = await callFn(...args);
|
|
4646
|
-
if (isReadableStream2(output)) {
|
|
4647
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4648
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4649
|
-
const durationMs2 = rawDateNow() - start;
|
|
4650
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4651
|
-
}).catch(() => {
|
|
4652
|
-
const durationMs2 = rawDateNow() - start;
|
|
4653
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
4654
|
-
});
|
|
4655
|
-
return streamForCaller;
|
|
4656
|
-
}
|
|
4657
|
-
if (isAsyncIterable2(output)) {
|
|
4658
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4659
|
-
const durationMs2 = rawDateNow() - start;
|
|
4660
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4661
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4662
|
-
});
|
|
4663
|
-
}
|
|
4664
|
-
const durationMs = rawDateNow() - start;
|
|
4665
|
-
const usage = extractUsage2(output);
|
|
4666
|
-
const event = {
|
|
4667
|
-
id: id2,
|
|
4668
|
-
type: "ai",
|
|
4669
|
-
name: modelName,
|
|
4670
|
-
input: input2,
|
|
4671
|
-
output,
|
|
4672
|
-
timestamp: start,
|
|
4673
|
-
durationMs,
|
|
4674
|
-
...usage ? { usage } : {}
|
|
4675
|
-
};
|
|
4676
|
-
pushTelemetryEvent(event);
|
|
4677
|
-
return output;
|
|
4678
|
-
} catch (e) {
|
|
4679
|
-
const durationMs = rawDateNow() - start;
|
|
4680
|
-
pushTelemetryEvent({
|
|
4681
|
-
id: id2,
|
|
4682
|
-
type: "ai",
|
|
4683
|
-
name: modelName,
|
|
4684
|
-
input: input2,
|
|
4685
|
-
output: { error: String(e) },
|
|
4686
|
-
timestamp: start,
|
|
4687
|
-
durationMs
|
|
4688
|
-
});
|
|
4689
|
-
throw e;
|
|
4690
|
-
}
|
|
4691
|
-
}
|
|
4692
|
-
if (ctx) {
|
|
4693
|
-
const { recorder, replay } = ctx;
|
|
4694
|
-
const id2 = recorder.nextId();
|
|
4695
|
-
if (replay.shouldReplay(id2)) {
|
|
4696
|
-
const historical = replay.getRecordedEvent(id2);
|
|
4697
|
-
if (historical?.streamed === true) {
|
|
4698
|
-
const raw = typeof historical.streamRaw === "string" ? historical.streamRaw : "";
|
|
4699
|
-
return reconstructStream3(raw);
|
|
4700
|
-
}
|
|
4701
|
-
return replay.getRecordedResult(id2);
|
|
4702
|
-
}
|
|
4703
|
-
const aiMock2 = resolveAIMock(modelName);
|
|
4704
|
-
if (aiMock2.mocked) {
|
|
4705
|
-
const input3 = args.length === 1 ? args[0] : args;
|
|
4706
|
-
const event = {
|
|
4707
|
-
id: id2,
|
|
4708
|
-
type: "ai",
|
|
4709
|
-
name: modelName,
|
|
4710
|
-
input: input3,
|
|
4711
|
-
output: aiMock2.result,
|
|
4712
|
-
timestamp: start,
|
|
4713
|
-
durationMs: 0
|
|
4714
|
-
};
|
|
4715
|
-
recorder.record(event);
|
|
4716
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4717
|
-
return aiMock2.result;
|
|
4718
|
-
}
|
|
4719
|
-
const rawInput = args.length === 1 ? args[0] : args;
|
|
4720
|
-
const promptModifiedInput = resolvePromptMock(rawInput);
|
|
4721
|
-
const userPromptModifiedInput = resolveUserPromptMock(promptModifiedInput !== void 0 ? promptModifiedInput : rawInput);
|
|
4722
|
-
const modifiedInput = userPromptModifiedInput !== void 0 ? userPromptModifiedInput : promptModifiedInput;
|
|
4723
|
-
const effectiveArgs = modifiedInput !== void 0 ? [modifiedInput] : args;
|
|
4724
|
-
const input2 = modifiedInput !== void 0 ? modifiedInput : rawInput;
|
|
4725
|
-
try {
|
|
4726
|
-
const output = await callFn(...effectiveArgs);
|
|
4727
|
-
if (isReadableStream2(output)) {
|
|
4728
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4729
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4730
|
-
const durationMs2 = rawDateNow() - start;
|
|
4731
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4732
|
-
recorder.record(event2);
|
|
4733
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4734
|
-
}).catch(() => {
|
|
4735
|
-
const durationMs2 = rawDateNow() - start;
|
|
4736
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 };
|
|
4737
|
-
recorder.record(event2);
|
|
4738
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4739
|
-
});
|
|
4740
|
-
return streamForCaller;
|
|
4741
|
-
}
|
|
4742
|
-
if (isAsyncIterable2(output)) {
|
|
4743
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4744
|
-
const durationMs2 = rawDateNow() - start;
|
|
4745
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4746
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4747
|
-
recorder.record(event2);
|
|
4748
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4749
|
-
});
|
|
4750
|
-
}
|
|
4751
|
-
const durationMs = rawDateNow() - start;
|
|
4752
|
-
const usage = extractUsage2(output);
|
|
4753
|
-
const event = {
|
|
4754
|
-
id: id2,
|
|
4755
|
-
type: "ai",
|
|
4756
|
-
name: modelName,
|
|
4757
|
-
input: input2,
|
|
4758
|
-
output,
|
|
4759
|
-
timestamp: start,
|
|
4760
|
-
durationMs,
|
|
4761
|
-
...usage ? { usage } : {}
|
|
4762
|
-
};
|
|
4763
|
-
recorder.record(event);
|
|
4764
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4765
|
-
return output;
|
|
4766
|
-
} catch (e) {
|
|
4767
|
-
const durationMs = rawDateNow() - start;
|
|
4768
|
-
const event = {
|
|
4769
|
-
id: id2,
|
|
4770
|
-
type: "ai",
|
|
4771
|
-
name: modelName,
|
|
4772
|
-
input: input2,
|
|
4773
|
-
output: { error: String(e) },
|
|
4774
|
-
timestamp: start,
|
|
4775
|
-
durationMs
|
|
4776
|
-
};
|
|
4777
|
-
recorder.record(event);
|
|
4778
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4779
|
-
throw e;
|
|
4780
|
-
}
|
|
4781
|
-
}
|
|
4782
|
-
const id = httpCtx.nextId();
|
|
4783
|
-
const frozen = getHttpFrozenEvent(id);
|
|
4784
|
-
if (frozen) {
|
|
4785
|
-
pushTelemetryEvent(frozen);
|
|
4786
|
-
if (frozen.streamed === true) {
|
|
4787
|
-
const raw = typeof frozen.streamRaw === "string" ? frozen.streamRaw : "";
|
|
4788
|
-
return reconstructStream3(raw);
|
|
4789
|
-
}
|
|
4790
|
-
return frozen.output;
|
|
4791
|
-
}
|
|
4792
|
-
const aiMock = getHttpAIMock(modelName);
|
|
4793
|
-
if (aiMock.mocked) {
|
|
4794
|
-
const input2 = args.length === 1 ? args[0] : args;
|
|
4795
|
-
const event = {
|
|
4796
|
-
id,
|
|
4797
|
-
type: "ai",
|
|
4798
|
-
name: modelName,
|
|
4799
|
-
input: input2,
|
|
4800
|
-
output: aiMock.result,
|
|
4801
|
-
timestamp: start,
|
|
4802
|
-
durationMs: 0
|
|
4803
|
-
};
|
|
4804
|
-
pushTelemetryEvent(event);
|
|
4805
|
-
return aiMock.result;
|
|
4806
|
-
}
|
|
4807
|
-
const rawHttpInput = args.length === 1 ? args[0] : args;
|
|
4808
|
-
const httpSystemModified = getHttpPromptMock(rawHttpInput);
|
|
4809
|
-
const httpUserModified = getHttpUserPromptMock(httpSystemModified !== void 0 ? httpSystemModified : rawHttpInput);
|
|
4810
|
-
const httpModifiedInput = httpUserModified !== void 0 ? httpUserModified : httpSystemModified;
|
|
4811
|
-
const httpEffectiveArgs = httpModifiedInput !== void 0 ? [httpModifiedInput] : args;
|
|
4812
|
-
const input = httpModifiedInput !== void 0 ? httpModifiedInput : rawHttpInput;
|
|
4813
|
-
try {
|
|
4814
|
-
const output = await callFn(...httpEffectiveArgs);
|
|
4815
|
-
if (isReadableStream2(output)) {
|
|
4816
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4817
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4818
|
-
const durationMs2 = rawDateNow() - start;
|
|
4819
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4820
|
-
}).catch(() => {
|
|
4821
|
-
const durationMs2 = rawDateNow() - start;
|
|
4822
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
4823
|
-
});
|
|
4824
|
-
return streamForCaller;
|
|
4825
|
-
}
|
|
4826
|
-
if (isAsyncIterable2(output)) {
|
|
4827
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4828
|
-
const durationMs2 = rawDateNow() - start;
|
|
4829
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4830
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4831
|
-
});
|
|
4832
|
-
}
|
|
4833
|
-
const durationMs = rawDateNow() - start;
|
|
4834
|
-
const usage = extractUsage2(output);
|
|
4835
|
-
const event = {
|
|
4836
|
-
id,
|
|
4837
|
-
type: "ai",
|
|
4838
|
-
name: modelName,
|
|
4839
|
-
input,
|
|
4840
|
-
output,
|
|
4841
|
-
timestamp: start,
|
|
4842
|
-
durationMs,
|
|
4843
|
-
...usage ? { usage } : {}
|
|
4844
|
-
};
|
|
4845
|
-
pushTelemetryEvent(event);
|
|
4846
|
-
return output;
|
|
4847
|
-
} catch (e) {
|
|
4848
|
-
const durationMs = rawDateNow() - start;
|
|
4849
|
-
pushTelemetryEvent({
|
|
4850
|
-
id,
|
|
4851
|
-
type: "ai",
|
|
4852
|
-
name: modelName,
|
|
4853
|
-
input,
|
|
4854
|
-
output: { error: String(e) },
|
|
4855
|
-
timestamp: start,
|
|
4856
|
-
durationMs
|
|
4857
|
-
});
|
|
4858
|
-
throw e;
|
|
4884
|
+
if (prev === void 0) delete g5[TOOL_WRAPPER_ACTIVE_KEY];
|
|
4885
|
+
else g5[TOOL_WRAPPER_ACTIVE_KEY] = prev;
|
|
4859
4886
|
}
|
|
4860
4887
|
};
|
|
4861
4888
|
}
|
|
4862
4889
|
|
|
4863
4890
|
// src/index.ts
|
|
4891
|
+
init_workflow_ai();
|
|
4864
4892
|
init_telemetry_push();
|
|
4865
4893
|
init_mock_resolver();
|
|
4866
4894
|
|