elasticdash-test 0.1.18-alpha-6 → 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 +427 -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/telemetry-push.d.ts +2 -0
- package/dist/interceptors/telemetry-push.d.ts.map +1 -1
- package/dist/interceptors/telemetry-push.js +4 -0
- package/dist/interceptors/telemetry-push.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/dist/trigger-executor.d.ts.map +1 -1
- package/dist/trigger-executor.js +8 -0
- package/dist/trigger-executor.js.map +1 -1
- package/package.json +1 -1
- package/src/interceptors/ai-interceptor.ts +7 -0
- package/src/interceptors/telemetry-push.ts +6 -0
- package/src/interceptors/workflow-ai.ts +26 -0
- package/src/trigger-executor.ts +8 -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/,
|
|
@@ -2905,6 +3250,8 @@ async function executeTrigger(serverUrl, apiKey, trigger) {
|
|
|
2905
3250
|
return;
|
|
2906
3251
|
}
|
|
2907
3252
|
handledTriggers.add(trigger.triggerId);
|
|
3253
|
+
const obsCtx = getObservabilityContext();
|
|
3254
|
+
if (obsCtx) obsCtx.isRerun = true;
|
|
2908
3255
|
const cwd = process.cwd();
|
|
2909
3256
|
const tools = scanTools(cwd);
|
|
2910
3257
|
const frozenEvents = trigger.frozenEvents || [];
|
|
@@ -2984,6 +3331,7 @@ async function executeTrigger(serverUrl, apiKey, trigger) {
|
|
|
2984
3331
|
debugLog(`[elasticdash] Trigger ${trigger.triggerId} step ${stepIndex + 1}/${totalSteps} POST to event ${step.originalEventDbId} failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2985
3332
|
}
|
|
2986
3333
|
}
|
|
3334
|
+
if (obsCtx) obsCtx.isRerun = false;
|
|
2987
3335
|
}
|
|
2988
3336
|
var handledTriggers;
|
|
2989
3337
|
var init_trigger_executor = __esm({
|
|
@@ -2991,6 +3339,7 @@ var init_trigger_executor = __esm({
|
|
|
2991
3339
|
"use strict";
|
|
2992
3340
|
init_portal_executor();
|
|
2993
3341
|
init_http();
|
|
3342
|
+
init_telemetry_push();
|
|
2994
3343
|
init_tool_runner();
|
|
2995
3344
|
init_debug();
|
|
2996
3345
|
handledTriggers = /* @__PURE__ */ new Set();
|
|
@@ -3290,14 +3639,14 @@ var init_observability = __esm({
|
|
|
3290
3639
|
// src/interceptors/telemetry-push.ts
|
|
3291
3640
|
function setObservabilityContext(ctx) {
|
|
3292
3641
|
obsAls.enterWith(ctx);
|
|
3293
|
-
|
|
3642
|
+
g4[GLOBAL_OBS_KEY] = ctx;
|
|
3294
3643
|
}
|
|
3295
3644
|
function getObservabilityContext() {
|
|
3296
|
-
return obsAls.getStore() ??
|
|
3645
|
+
return obsAls.getStore() ?? g4[GLOBAL_OBS_KEY];
|
|
3297
3646
|
}
|
|
3298
3647
|
function clearObservabilityContext() {
|
|
3299
3648
|
obsAls.enterWith(void 0);
|
|
3300
|
-
|
|
3649
|
+
g4[GLOBAL_OBS_KEY] = void 0;
|
|
3301
3650
|
}
|
|
3302
3651
|
function buildContext(runId, dashboardUrl, frozenEvents, promptMocksRecord = {}, toolMockConfig, aiMockConfig, userPromptMocks) {
|
|
3303
3652
|
let counter = 0;
|
|
@@ -3319,15 +3668,15 @@ function buildContext(runId, dashboardUrl, frozenEvents, promptMocksRecord = {},
|
|
|
3319
3668
|
};
|
|
3320
3669
|
}
|
|
3321
3670
|
function setGlobalHttpContext(ctx) {
|
|
3322
|
-
|
|
3671
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3323
3672
|
}
|
|
3324
3673
|
function clearGlobalHttpContext() {
|
|
3325
|
-
|
|
3674
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3326
3675
|
}
|
|
3327
3676
|
function setHttpRunContext(runId, dashboardUrl) {
|
|
3328
3677
|
const ctx = buildContext(runId, dashboardUrl, [], {});
|
|
3329
3678
|
httpRunAls.enterWith(ctx);
|
|
3330
|
-
|
|
3679
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3331
3680
|
ensureInterceptorsInstalled().catch(() => {
|
|
3332
3681
|
});
|
|
3333
3682
|
}
|
|
@@ -3357,11 +3706,11 @@ async function initHttpRunContext(runId, dashboardUrl) {
|
|
|
3357
3706
|
}
|
|
3358
3707
|
const ctx = buildContext(runId, dashboardUrl, frozenEvents, promptMocks, toolMockConfig, aiMockConfig, userPromptMocks);
|
|
3359
3708
|
httpRunAls.enterWith(ctx);
|
|
3360
|
-
|
|
3709
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3361
3710
|
await ensureInterceptorsInstalled();
|
|
3362
3711
|
}
|
|
3363
3712
|
function getHttpRunContext() {
|
|
3364
|
-
return httpRunAls.getStore() ??
|
|
3713
|
+
return httpRunAls.getStore() ?? g4[GLOBAL_CTX_KEY];
|
|
3365
3714
|
}
|
|
3366
3715
|
function getHttpFrozenEvent(id) {
|
|
3367
3716
|
return getHttpRunContext()?.frozenEvents.get(id);
|
|
@@ -3469,6 +3818,9 @@ function pushTelemetryEvent(event, explicitCtx) {
|
|
|
3469
3818
|
if (!event.traceId && obsCtx.traceId) {
|
|
3470
3819
|
event.traceId = obsCtx.traceId;
|
|
3471
3820
|
}
|
|
3821
|
+
if (obsCtx.isRerun) {
|
|
3822
|
+
event.isRerun = true;
|
|
3823
|
+
}
|
|
3472
3824
|
obsCtx.batcher.enqueue(event);
|
|
3473
3825
|
return;
|
|
3474
3826
|
}
|
|
@@ -3490,8 +3842,8 @@ function pushTelemetryEvent(event, explicitCtx) {
|
|
|
3490
3842
|
});
|
|
3491
3843
|
}
|
|
3492
3844
|
async function ensureInterceptorsInstalled() {
|
|
3493
|
-
if (
|
|
3494
|
-
|
|
3845
|
+
if (g4[INTERCEPTORS_KEY]) return;
|
|
3846
|
+
g4[INTERCEPTORS_KEY] = true;
|
|
3495
3847
|
try {
|
|
3496
3848
|
const [httpMod, aiMod, dbMod] = await Promise.all([
|
|
3497
3849
|
Promise.resolve().then(() => (init_http(), http_exports)),
|
|
@@ -3507,11 +3859,11 @@ async function ensureInterceptorsInstalled() {
|
|
|
3507
3859
|
async function runInHttpContext(runId, dashboardUrl, callback) {
|
|
3508
3860
|
await ensureInterceptorsInstalled();
|
|
3509
3861
|
const ctx = buildContext(runId, dashboardUrl, [], {});
|
|
3510
|
-
|
|
3862
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3511
3863
|
try {
|
|
3512
3864
|
return await httpRunAls.run(ctx, callback);
|
|
3513
3865
|
} finally {
|
|
3514
|
-
|
|
3866
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3515
3867
|
}
|
|
3516
3868
|
}
|
|
3517
3869
|
async function runWithInitializedHttpContext(runId, dashboardUrl, callback) {
|
|
@@ -3548,11 +3900,11 @@ async function runWithInitializedHttpContext(runId, dashboardUrl, callback) {
|
|
|
3548
3900
|
}
|
|
3549
3901
|
await ensureInterceptorsInstalled();
|
|
3550
3902
|
const ctx = buildContext(runId, dashboardUrl, frozenEvents, promptMocks, toolMockConfig, aiMockConfig, userPromptMocks);
|
|
3551
|
-
|
|
3903
|
+
g4[GLOBAL_CTX_KEY] = ctx;
|
|
3552
3904
|
try {
|
|
3553
3905
|
return await httpRunAls.run(ctx, callback);
|
|
3554
3906
|
} finally {
|
|
3555
|
-
|
|
3907
|
+
g4[GLOBAL_CTX_KEY] = void 0;
|
|
3556
3908
|
}
|
|
3557
3909
|
}
|
|
3558
3910
|
async function tryAutoInitHttpContext() {
|
|
@@ -3561,8 +3913,8 @@ async function tryAutoInitHttpContext() {
|
|
|
3561
3913
|
const apiUrl = (typeof process !== "undefined" && process.env?.ELASTICDASH_API_URL) ?? "";
|
|
3562
3914
|
if (apiUrl) {
|
|
3563
3915
|
const obsInitKey = "__elasticdash_obs_auto_init__";
|
|
3564
|
-
if (!
|
|
3565
|
-
|
|
3916
|
+
if (!g4[obsInitKey]) {
|
|
3917
|
+
g4[obsInitKey] = (async () => {
|
|
3566
3918
|
try {
|
|
3567
3919
|
const { initObservability: initObservability2 } = await Promise.resolve().then(() => (init_observability(), observability_exports));
|
|
3568
3920
|
initObservability2({
|
|
@@ -3575,13 +3927,13 @@ async function tryAutoInitHttpContext() {
|
|
|
3575
3927
|
}
|
|
3576
3928
|
})();
|
|
3577
3929
|
}
|
|
3578
|
-
await
|
|
3930
|
+
await g4[obsInitKey];
|
|
3579
3931
|
return;
|
|
3580
3932
|
}
|
|
3581
3933
|
const serverUrl = (typeof process !== "undefined" && process.env?.ELASTICDASH_SERVER) ?? "";
|
|
3582
3934
|
if (!serverUrl) return;
|
|
3583
|
-
if (!
|
|
3584
|
-
|
|
3935
|
+
if (!g4[AUTO_INIT_KEY]) {
|
|
3936
|
+
g4[AUTO_INIT_KEY] = (async () => {
|
|
3585
3937
|
try {
|
|
3586
3938
|
const runId = (typeof process !== "undefined" && process.env?.ELASTICDASH_RUN_ID) ?? "";
|
|
3587
3939
|
if (runId) {
|
|
@@ -3593,9 +3945,9 @@ async function tryAutoInitHttpContext() {
|
|
|
3593
3945
|
}
|
|
3594
3946
|
})();
|
|
3595
3947
|
}
|
|
3596
|
-
await
|
|
3948
|
+
await g4[AUTO_INIT_KEY];
|
|
3597
3949
|
}
|
|
3598
|
-
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;
|
|
3599
3951
|
var init_telemetry_push = __esm({
|
|
3600
3952
|
"src/interceptors/telemetry-push.ts"() {
|
|
3601
3953
|
"use strict";
|
|
@@ -3603,15 +3955,15 @@ var init_telemetry_push = __esm({
|
|
|
3603
3955
|
import_node_crypto4 = require("node:crypto");
|
|
3604
3956
|
init_mock_resolver();
|
|
3605
3957
|
init_debug();
|
|
3606
|
-
|
|
3958
|
+
g4 = globalThis;
|
|
3607
3959
|
HTTP_RUN_ALS_KEY = "__elasticdash_http_run_als__";
|
|
3608
3960
|
GLOBAL_CTX_KEY = "__elasticdash_global_http_ctx__";
|
|
3609
3961
|
OBS_ALS_KEY = "__elasticdash_obs_als__";
|
|
3610
3962
|
GLOBAL_OBS_KEY = "__elasticdash_global_obs_ctx__";
|
|
3611
|
-
httpRunAls =
|
|
3612
|
-
if (!
|
|
3613
|
-
obsAls =
|
|
3614
|
-
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;
|
|
3615
3967
|
INTERCEPTORS_KEY = "__elasticdash_interceptors_installed__";
|
|
3616
3968
|
AUTO_INIT_KEY = "__elasticdash_auto_init_promise__";
|
|
3617
3969
|
}
|
|
@@ -4308,13 +4660,13 @@ function toTraceArgs2(input) {
|
|
|
4308
4660
|
if (input === void 0) return void 0;
|
|
4309
4661
|
return { value: input };
|
|
4310
4662
|
}
|
|
4311
|
-
function
|
|
4663
|
+
function isReadableStream2(v) {
|
|
4312
4664
|
return typeof v === "object" && v !== null && typeof v.getReader === "function" && typeof v.tee === "function";
|
|
4313
4665
|
}
|
|
4314
|
-
function
|
|
4666
|
+
function isAsyncIterable2(v) {
|
|
4315
4667
|
return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
|
|
4316
4668
|
}
|
|
4317
|
-
async function
|
|
4669
|
+
async function bufferReadableStream2(stream) {
|
|
4318
4670
|
const decoder = new TextDecoder();
|
|
4319
4671
|
const reader = stream.getReader();
|
|
4320
4672
|
let raw = "";
|
|
@@ -4329,7 +4681,7 @@ async function bufferReadableStream(stream) {
|
|
|
4329
4681
|
}
|
|
4330
4682
|
return raw;
|
|
4331
4683
|
}
|
|
4332
|
-
function
|
|
4684
|
+
function reconstructStream3(raw) {
|
|
4333
4685
|
const encoder = new TextEncoder();
|
|
4334
4686
|
return new ReadableStream({
|
|
4335
4687
|
start(ctrl) {
|
|
@@ -4338,7 +4690,7 @@ function reconstructStream2(raw) {
|
|
|
4338
4690
|
}
|
|
4339
4691
|
});
|
|
4340
4692
|
}
|
|
4341
|
-
function
|
|
4693
|
+
function wrapAsyncIterable2(source, onComplete) {
|
|
4342
4694
|
return {
|
|
4343
4695
|
[Symbol.asyncIterator]() {
|
|
4344
4696
|
const iter = source[Symbol.asyncIterator]();
|
|
@@ -4378,9 +4730,9 @@ function wrapTool(name, fn) {
|
|
|
4378
4730
|
try {
|
|
4379
4731
|
const output = await fn(...args);
|
|
4380
4732
|
const durationMs = rawDateNow() - start2;
|
|
4381
|
-
if (
|
|
4733
|
+
if (isReadableStream2(output)) {
|
|
4382
4734
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4383
|
-
|
|
4735
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4384
4736
|
const durationMs2 = rawDateNow() - start2;
|
|
4385
4737
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
4386
4738
|
}).catch(() => {
|
|
@@ -4389,8 +4741,8 @@ function wrapTool(name, fn) {
|
|
|
4389
4741
|
});
|
|
4390
4742
|
return streamForCaller;
|
|
4391
4743
|
}
|
|
4392
|
-
if (
|
|
4393
|
-
return
|
|
4744
|
+
if (isAsyncIterable2(output)) {
|
|
4745
|
+
return wrapAsyncIterable2(output, (chunks) => {
|
|
4394
4746
|
const durationMs2 = rawDateNow() - start2;
|
|
4395
4747
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4396
4748
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
@@ -4412,7 +4764,7 @@ function wrapTool(name, fn) {
|
|
|
4412
4764
|
pushTelemetryEvent(frozen);
|
|
4413
4765
|
if (frozen.streamed === true) {
|
|
4414
4766
|
const raw = typeof frozen.streamRaw === "string" ? frozen.streamRaw : "";
|
|
4415
|
-
return
|
|
4767
|
+
return reconstructStream3(raw);
|
|
4416
4768
|
}
|
|
4417
4769
|
return frozen.output;
|
|
4418
4770
|
}
|
|
@@ -4425,9 +4777,9 @@ function wrapTool(name, fn) {
|
|
|
4425
4777
|
const start2 = rawDateNow();
|
|
4426
4778
|
try {
|
|
4427
4779
|
const output = await fn(...args);
|
|
4428
|
-
if (
|
|
4780
|
+
if (isReadableStream2(output)) {
|
|
4429
4781
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4430
|
-
|
|
4782
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4431
4783
|
const durationMs2 = rawDateNow() - start2;
|
|
4432
4784
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
4433
4785
|
}).catch(() => {
|
|
@@ -4436,8 +4788,8 @@ function wrapTool(name, fn) {
|
|
|
4436
4788
|
});
|
|
4437
4789
|
return streamForCaller;
|
|
4438
4790
|
}
|
|
4439
|
-
if (
|
|
4440
|
-
return
|
|
4791
|
+
if (isAsyncIterable2(output)) {
|
|
4792
|
+
return wrapAsyncIterable2(output, (chunks) => {
|
|
4441
4793
|
const durationMs2 = rawDateNow() - start2;
|
|
4442
4794
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4443
4795
|
pushTelemetryEvent({ id: id2, type: "tool", name, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start2, durationMs: durationMs2 });
|
|
@@ -4461,7 +4813,7 @@ function wrapTool(name, fn) {
|
|
|
4461
4813
|
if (historical) recorder.record(historical);
|
|
4462
4814
|
if (historical?.streamed === true) {
|
|
4463
4815
|
const raw = typeof historical.streamRaw === "string" ? historical.streamRaw : "";
|
|
4464
|
-
const stream =
|
|
4816
|
+
const stream = reconstructStream3(raw);
|
|
4465
4817
|
if (trace && typeof trace.recordToolCall === "function") {
|
|
4466
4818
|
trace.recordToolCall({ name, args: toTraceArgs2(input), result: stream, workflowEventId: id });
|
|
4467
4819
|
}
|
|
@@ -4473,15 +4825,15 @@ function wrapTool(name, fn) {
|
|
|
4473
4825
|
}
|
|
4474
4826
|
return replayed;
|
|
4475
4827
|
}
|
|
4476
|
-
const
|
|
4477
|
-
const prev =
|
|
4478
|
-
|
|
4828
|
+
const g5 = globalThis;
|
|
4829
|
+
const prev = g5[TOOL_WRAPPER_ACTIVE_KEY];
|
|
4830
|
+
g5[TOOL_WRAPPER_ACTIVE_KEY] = true;
|
|
4479
4831
|
const start = rawDateNow();
|
|
4480
4832
|
try {
|
|
4481
4833
|
const output = await fn(...args);
|
|
4482
|
-
if (
|
|
4834
|
+
if (isReadableStream2(output)) {
|
|
4483
4835
|
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4484
|
-
|
|
4836
|
+
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4485
4837
|
const durationMs2 = rawDateNow() - start;
|
|
4486
4838
|
const event = { id, type: "tool", name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4487
4839
|
recorder.record(event);
|
|
@@ -4498,8 +4850,8 @@ function wrapTool(name, fn) {
|
|
|
4498
4850
|
}
|
|
4499
4851
|
return result;
|
|
4500
4852
|
}
|
|
4501
|
-
if (
|
|
4502
|
-
const wrapped =
|
|
4853
|
+
if (isAsyncIterable2(output)) {
|
|
4854
|
+
const wrapped = wrapAsyncIterable2(output, (chunks) => {
|
|
4503
4855
|
const durationMs2 = rawDateNow() - start;
|
|
4504
4856
|
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4505
4857
|
const event = { id, type: "tool", name, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
@@ -4529,331 +4881,14 @@ function wrapTool(name, fn) {
|
|
|
4529
4881
|
}
|
|
4530
4882
|
throw e;
|
|
4531
4883
|
} finally {
|
|
4532
|
-
if (prev === void 0) delete
|
|
4533
|
-
else
|
|
4534
|
-
}
|
|
4535
|
-
};
|
|
4536
|
-
}
|
|
4537
|
-
|
|
4538
|
-
// src/interceptors/workflow-ai.ts
|
|
4539
|
-
init_recorder();
|
|
4540
|
-
init_side_effects();
|
|
4541
|
-
init_telemetry_push();
|
|
4542
|
-
init_mock_resolver();
|
|
4543
|
-
function extractUsage2(output) {
|
|
4544
|
-
if (!output || typeof output !== "object") return void 0;
|
|
4545
|
-
const o = output;
|
|
4546
|
-
if (o.usage && typeof o.usage === "object") {
|
|
4547
|
-
const u = o.usage;
|
|
4548
|
-
if (u.input_tokens != null || u.output_tokens != null) {
|
|
4549
|
-
return {
|
|
4550
|
-
inputTokens: u.input_tokens,
|
|
4551
|
-
outputTokens: u.output_tokens,
|
|
4552
|
-
totalTokens: (u.input_tokens ?? 0) + (u.output_tokens ?? 0)
|
|
4553
|
-
};
|
|
4554
|
-
}
|
|
4555
|
-
if (u.prompt_tokens != null || u.completion_tokens != null) {
|
|
4556
|
-
return {
|
|
4557
|
-
inputTokens: u.prompt_tokens,
|
|
4558
|
-
outputTokens: u.completion_tokens,
|
|
4559
|
-
totalTokens: u.total_tokens
|
|
4560
|
-
};
|
|
4561
|
-
}
|
|
4562
|
-
}
|
|
4563
|
-
if (o.usageMetadata && typeof o.usageMetadata === "object") {
|
|
4564
|
-
const u = o.usageMetadata;
|
|
4565
|
-
return {
|
|
4566
|
-
inputTokens: u.promptTokenCount,
|
|
4567
|
-
outputTokens: u.candidatesTokenCount,
|
|
4568
|
-
totalTokens: u.totalTokenCount
|
|
4569
|
-
};
|
|
4570
|
-
}
|
|
4571
|
-
return void 0;
|
|
4572
|
-
}
|
|
4573
|
-
function isReadableStream2(v) {
|
|
4574
|
-
return typeof v === "object" && v !== null && typeof v.getReader === "function" && typeof v.tee === "function";
|
|
4575
|
-
}
|
|
4576
|
-
function isAsyncIterable2(v) {
|
|
4577
|
-
return typeof v === "object" && v !== null && Symbol.asyncIterator in v;
|
|
4578
|
-
}
|
|
4579
|
-
async function bufferReadableStream2(stream) {
|
|
4580
|
-
const decoder = new TextDecoder();
|
|
4581
|
-
const reader = stream.getReader();
|
|
4582
|
-
let raw = "";
|
|
4583
|
-
try {
|
|
4584
|
-
for (; ; ) {
|
|
4585
|
-
const { done, value } = await reader.read();
|
|
4586
|
-
if (done) break;
|
|
4587
|
-
raw += decoder.decode(value, { stream: true });
|
|
4588
|
-
}
|
|
4589
|
-
} finally {
|
|
4590
|
-
reader.releaseLock();
|
|
4591
|
-
}
|
|
4592
|
-
return raw;
|
|
4593
|
-
}
|
|
4594
|
-
function reconstructStream3(raw) {
|
|
4595
|
-
const encoder = new TextEncoder();
|
|
4596
|
-
return new ReadableStream({
|
|
4597
|
-
start(ctrl) {
|
|
4598
|
-
ctrl.enqueue(encoder.encode(raw));
|
|
4599
|
-
ctrl.close();
|
|
4600
|
-
}
|
|
4601
|
-
});
|
|
4602
|
-
}
|
|
4603
|
-
function wrapAsyncIterable2(source, onComplete) {
|
|
4604
|
-
return {
|
|
4605
|
-
[Symbol.asyncIterator]() {
|
|
4606
|
-
const iter = source[Symbol.asyncIterator]();
|
|
4607
|
-
const collected = [];
|
|
4608
|
-
return {
|
|
4609
|
-
async next() {
|
|
4610
|
-
const result = await iter.next();
|
|
4611
|
-
if (!result.done) {
|
|
4612
|
-
collected.push(result.value);
|
|
4613
|
-
} else {
|
|
4614
|
-
onComplete(collected);
|
|
4615
|
-
}
|
|
4616
|
-
return result;
|
|
4617
|
-
},
|
|
4618
|
-
async return(value) {
|
|
4619
|
-
onComplete(collected);
|
|
4620
|
-
return iter.return ? iter.return(value) : { done: true, value: void 0 };
|
|
4621
|
-
}
|
|
4622
|
-
};
|
|
4623
|
-
}
|
|
4624
|
-
};
|
|
4625
|
-
}
|
|
4626
|
-
function wrapAI(modelName, callFn) {
|
|
4627
|
-
return async (...args) => {
|
|
4628
|
-
await tryAutoInitHttpContext();
|
|
4629
|
-
const ctx = getCaptureContext();
|
|
4630
|
-
const httpCtx = getHttpRunContext();
|
|
4631
|
-
const obsCtx = getObservabilityContext();
|
|
4632
|
-
if (!ctx && !httpCtx && !obsCtx) return callFn(...args);
|
|
4633
|
-
const start = rawDateNow();
|
|
4634
|
-
if (!ctx && !httpCtx && obsCtx) {
|
|
4635
|
-
const id2 = obsCtx.nextId();
|
|
4636
|
-
const input2 = args.length === 1 ? args[0] : args;
|
|
4637
|
-
try {
|
|
4638
|
-
const output = await callFn(...args);
|
|
4639
|
-
if (isReadableStream2(output)) {
|
|
4640
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4641
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4642
|
-
const durationMs2 = rawDateNow() - start;
|
|
4643
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4644
|
-
}).catch(() => {
|
|
4645
|
-
const durationMs2 = rawDateNow() - start;
|
|
4646
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
4647
|
-
});
|
|
4648
|
-
return streamForCaller;
|
|
4649
|
-
}
|
|
4650
|
-
if (isAsyncIterable2(output)) {
|
|
4651
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4652
|
-
const durationMs2 = rawDateNow() - start;
|
|
4653
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4654
|
-
pushTelemetryEvent({ id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4655
|
-
});
|
|
4656
|
-
}
|
|
4657
|
-
const durationMs = rawDateNow() - start;
|
|
4658
|
-
const usage = extractUsage2(output);
|
|
4659
|
-
const event = {
|
|
4660
|
-
id: id2,
|
|
4661
|
-
type: "ai",
|
|
4662
|
-
name: modelName,
|
|
4663
|
-
input: input2,
|
|
4664
|
-
output,
|
|
4665
|
-
timestamp: start,
|
|
4666
|
-
durationMs,
|
|
4667
|
-
...usage ? { usage } : {}
|
|
4668
|
-
};
|
|
4669
|
-
pushTelemetryEvent(event);
|
|
4670
|
-
return output;
|
|
4671
|
-
} catch (e) {
|
|
4672
|
-
const durationMs = rawDateNow() - start;
|
|
4673
|
-
pushTelemetryEvent({
|
|
4674
|
-
id: id2,
|
|
4675
|
-
type: "ai",
|
|
4676
|
-
name: modelName,
|
|
4677
|
-
input: input2,
|
|
4678
|
-
output: { error: String(e) },
|
|
4679
|
-
timestamp: start,
|
|
4680
|
-
durationMs
|
|
4681
|
-
});
|
|
4682
|
-
throw e;
|
|
4683
|
-
}
|
|
4684
|
-
}
|
|
4685
|
-
if (ctx) {
|
|
4686
|
-
const { recorder, replay } = ctx;
|
|
4687
|
-
const id2 = recorder.nextId();
|
|
4688
|
-
if (replay.shouldReplay(id2)) {
|
|
4689
|
-
const historical = replay.getRecordedEvent(id2);
|
|
4690
|
-
if (historical?.streamed === true) {
|
|
4691
|
-
const raw = typeof historical.streamRaw === "string" ? historical.streamRaw : "";
|
|
4692
|
-
return reconstructStream3(raw);
|
|
4693
|
-
}
|
|
4694
|
-
return replay.getRecordedResult(id2);
|
|
4695
|
-
}
|
|
4696
|
-
const aiMock2 = resolveAIMock(modelName);
|
|
4697
|
-
if (aiMock2.mocked) {
|
|
4698
|
-
const input3 = args.length === 1 ? args[0] : args;
|
|
4699
|
-
const event = {
|
|
4700
|
-
id: id2,
|
|
4701
|
-
type: "ai",
|
|
4702
|
-
name: modelName,
|
|
4703
|
-
input: input3,
|
|
4704
|
-
output: aiMock2.result,
|
|
4705
|
-
timestamp: start,
|
|
4706
|
-
durationMs: 0
|
|
4707
|
-
};
|
|
4708
|
-
recorder.record(event);
|
|
4709
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4710
|
-
return aiMock2.result;
|
|
4711
|
-
}
|
|
4712
|
-
const rawInput = args.length === 1 ? args[0] : args;
|
|
4713
|
-
const promptModifiedInput = resolvePromptMock(rawInput);
|
|
4714
|
-
const userPromptModifiedInput = resolveUserPromptMock(promptModifiedInput !== void 0 ? promptModifiedInput : rawInput);
|
|
4715
|
-
const modifiedInput = userPromptModifiedInput !== void 0 ? userPromptModifiedInput : promptModifiedInput;
|
|
4716
|
-
const effectiveArgs = modifiedInput !== void 0 ? [modifiedInput] : args;
|
|
4717
|
-
const input2 = modifiedInput !== void 0 ? modifiedInput : rawInput;
|
|
4718
|
-
try {
|
|
4719
|
-
const output = await callFn(...effectiveArgs);
|
|
4720
|
-
if (isReadableStream2(output)) {
|
|
4721
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4722
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4723
|
-
const durationMs2 = rawDateNow() - start;
|
|
4724
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4725
|
-
recorder.record(event2);
|
|
4726
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4727
|
-
}).catch(() => {
|
|
4728
|
-
const durationMs2 = rawDateNow() - start;
|
|
4729
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 };
|
|
4730
|
-
recorder.record(event2);
|
|
4731
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4732
|
-
});
|
|
4733
|
-
return streamForCaller;
|
|
4734
|
-
}
|
|
4735
|
-
if (isAsyncIterable2(output)) {
|
|
4736
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4737
|
-
const durationMs2 = rawDateNow() - start;
|
|
4738
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4739
|
-
const event2 = { id: id2, type: "ai", name: modelName, input: input2, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 };
|
|
4740
|
-
recorder.record(event2);
|
|
4741
|
-
if (httpCtx) pushTelemetryEvent(event2);
|
|
4742
|
-
});
|
|
4743
|
-
}
|
|
4744
|
-
const durationMs = rawDateNow() - start;
|
|
4745
|
-
const usage = extractUsage2(output);
|
|
4746
|
-
const event = {
|
|
4747
|
-
id: id2,
|
|
4748
|
-
type: "ai",
|
|
4749
|
-
name: modelName,
|
|
4750
|
-
input: input2,
|
|
4751
|
-
output,
|
|
4752
|
-
timestamp: start,
|
|
4753
|
-
durationMs,
|
|
4754
|
-
...usage ? { usage } : {}
|
|
4755
|
-
};
|
|
4756
|
-
recorder.record(event);
|
|
4757
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4758
|
-
return output;
|
|
4759
|
-
} catch (e) {
|
|
4760
|
-
const durationMs = rawDateNow() - start;
|
|
4761
|
-
const event = {
|
|
4762
|
-
id: id2,
|
|
4763
|
-
type: "ai",
|
|
4764
|
-
name: modelName,
|
|
4765
|
-
input: input2,
|
|
4766
|
-
output: { error: String(e) },
|
|
4767
|
-
timestamp: start,
|
|
4768
|
-
durationMs
|
|
4769
|
-
};
|
|
4770
|
-
recorder.record(event);
|
|
4771
|
-
if (httpCtx) pushTelemetryEvent(event);
|
|
4772
|
-
throw e;
|
|
4773
|
-
}
|
|
4774
|
-
}
|
|
4775
|
-
const id = httpCtx.nextId();
|
|
4776
|
-
const frozen = getHttpFrozenEvent(id);
|
|
4777
|
-
if (frozen) {
|
|
4778
|
-
pushTelemetryEvent(frozen);
|
|
4779
|
-
if (frozen.streamed === true) {
|
|
4780
|
-
const raw = typeof frozen.streamRaw === "string" ? frozen.streamRaw : "";
|
|
4781
|
-
return reconstructStream3(raw);
|
|
4782
|
-
}
|
|
4783
|
-
return frozen.output;
|
|
4784
|
-
}
|
|
4785
|
-
const aiMock = getHttpAIMock(modelName);
|
|
4786
|
-
if (aiMock.mocked) {
|
|
4787
|
-
const input2 = args.length === 1 ? args[0] : args;
|
|
4788
|
-
const event = {
|
|
4789
|
-
id,
|
|
4790
|
-
type: "ai",
|
|
4791
|
-
name: modelName,
|
|
4792
|
-
input: input2,
|
|
4793
|
-
output: aiMock.result,
|
|
4794
|
-
timestamp: start,
|
|
4795
|
-
durationMs: 0
|
|
4796
|
-
};
|
|
4797
|
-
pushTelemetryEvent(event);
|
|
4798
|
-
return aiMock.result;
|
|
4799
|
-
}
|
|
4800
|
-
const rawHttpInput = args.length === 1 ? args[0] : args;
|
|
4801
|
-
const httpSystemModified = getHttpPromptMock(rawHttpInput);
|
|
4802
|
-
const httpUserModified = getHttpUserPromptMock(httpSystemModified !== void 0 ? httpSystemModified : rawHttpInput);
|
|
4803
|
-
const httpModifiedInput = httpUserModified !== void 0 ? httpUserModified : httpSystemModified;
|
|
4804
|
-
const httpEffectiveArgs = httpModifiedInput !== void 0 ? [httpModifiedInput] : args;
|
|
4805
|
-
const input = httpModifiedInput !== void 0 ? httpModifiedInput : rawHttpInput;
|
|
4806
|
-
try {
|
|
4807
|
-
const output = await callFn(...httpEffectiveArgs);
|
|
4808
|
-
if (isReadableStream2(output)) {
|
|
4809
|
-
const [streamForCaller, streamForRecorder] = output.tee();
|
|
4810
|
-
bufferReadableStream2(streamForRecorder).then((rawText) => {
|
|
4811
|
-
const durationMs2 = rawDateNow() - start;
|
|
4812
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4813
|
-
}).catch(() => {
|
|
4814
|
-
const durationMs2 = rawDateNow() - start;
|
|
4815
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: "", timestamp: start, durationMs: durationMs2 });
|
|
4816
|
-
});
|
|
4817
|
-
return streamForCaller;
|
|
4818
|
-
}
|
|
4819
|
-
if (isAsyncIterable2(output)) {
|
|
4820
|
-
return wrapAsyncIterable2(output, (chunks) => {
|
|
4821
|
-
const durationMs2 = rawDateNow() - start;
|
|
4822
|
-
const rawText = chunks.map((c) => typeof c === "string" ? c : JSON.stringify(c)).join("");
|
|
4823
|
-
pushTelemetryEvent({ id, type: "ai", name: modelName, input, output: null, streamed: true, streamRaw: rawText, timestamp: start, durationMs: durationMs2 });
|
|
4824
|
-
});
|
|
4825
|
-
}
|
|
4826
|
-
const durationMs = rawDateNow() - start;
|
|
4827
|
-
const usage = extractUsage2(output);
|
|
4828
|
-
const event = {
|
|
4829
|
-
id,
|
|
4830
|
-
type: "ai",
|
|
4831
|
-
name: modelName,
|
|
4832
|
-
input,
|
|
4833
|
-
output,
|
|
4834
|
-
timestamp: start,
|
|
4835
|
-
durationMs,
|
|
4836
|
-
...usage ? { usage } : {}
|
|
4837
|
-
};
|
|
4838
|
-
pushTelemetryEvent(event);
|
|
4839
|
-
return output;
|
|
4840
|
-
} catch (e) {
|
|
4841
|
-
const durationMs = rawDateNow() - start;
|
|
4842
|
-
pushTelemetryEvent({
|
|
4843
|
-
id,
|
|
4844
|
-
type: "ai",
|
|
4845
|
-
name: modelName,
|
|
4846
|
-
input,
|
|
4847
|
-
output: { error: String(e) },
|
|
4848
|
-
timestamp: start,
|
|
4849
|
-
durationMs
|
|
4850
|
-
});
|
|
4851
|
-
throw e;
|
|
4884
|
+
if (prev === void 0) delete g5[TOOL_WRAPPER_ACTIVE_KEY];
|
|
4885
|
+
else g5[TOOL_WRAPPER_ACTIVE_KEY] = prev;
|
|
4852
4886
|
}
|
|
4853
4887
|
};
|
|
4854
4888
|
}
|
|
4855
4889
|
|
|
4856
4890
|
// src/index.ts
|
|
4891
|
+
init_workflow_ai();
|
|
4857
4892
|
init_telemetry_push();
|
|
4858
4893
|
init_mock_resolver();
|
|
4859
4894
|
|