@opperai/agents 0.1.3 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/index.cjs +665 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +179 -1
- package/dist/index.d.ts +179 -1
- package/dist/index.js +661 -7
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -394,7 +394,11 @@ var HookEvents = {
|
|
|
394
394
|
ToolError: "tool:error",
|
|
395
395
|
MemoryRead: "memory:read",
|
|
396
396
|
MemoryWrite: "memory:write",
|
|
397
|
-
MemoryError: "memory:error"
|
|
397
|
+
MemoryError: "memory:error",
|
|
398
|
+
StreamStart: "stream:start",
|
|
399
|
+
StreamChunk: "stream:chunk",
|
|
400
|
+
StreamEnd: "stream:end",
|
|
401
|
+
StreamError: "stream:error"
|
|
398
402
|
};
|
|
399
403
|
var HookManager = class {
|
|
400
404
|
registry = /* @__PURE__ */ new Map();
|
|
@@ -466,6 +470,82 @@ var HookManager = class {
|
|
|
466
470
|
};
|
|
467
471
|
var createHookManager = (logger) => new HookManager(logger);
|
|
468
472
|
|
|
473
|
+
// src/base/events.ts
|
|
474
|
+
var AgentEvents = {
|
|
475
|
+
StreamStart: HookEvents.StreamStart,
|
|
476
|
+
StreamChunk: HookEvents.StreamChunk,
|
|
477
|
+
StreamEnd: HookEvents.StreamEnd,
|
|
478
|
+
StreamError: HookEvents.StreamError
|
|
479
|
+
};
|
|
480
|
+
var AgentEventEmitter = class {
|
|
481
|
+
registry = /* @__PURE__ */ new Map();
|
|
482
|
+
logger;
|
|
483
|
+
constructor(logger) {
|
|
484
|
+
this.logger = logger ?? getDefaultLogger();
|
|
485
|
+
}
|
|
486
|
+
on(event, listener) {
|
|
487
|
+
const listeners = this.registry.get(event) ?? /* @__PURE__ */ new Set();
|
|
488
|
+
listeners.add(listener);
|
|
489
|
+
this.registry.set(event, listeners);
|
|
490
|
+
return () => this.off(event, listener);
|
|
491
|
+
}
|
|
492
|
+
once(event, listener) {
|
|
493
|
+
const wrapper = (payload) => {
|
|
494
|
+
try {
|
|
495
|
+
listener(payload);
|
|
496
|
+
} finally {
|
|
497
|
+
this.off(event, wrapper);
|
|
498
|
+
}
|
|
499
|
+
};
|
|
500
|
+
return this.on(event, wrapper);
|
|
501
|
+
}
|
|
502
|
+
off(event, listener) {
|
|
503
|
+
const listeners = this.registry.get(event);
|
|
504
|
+
if (!listeners) {
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
listeners.delete(listener);
|
|
508
|
+
if (listeners.size === 0) {
|
|
509
|
+
this.registry.delete(event);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
emit(event, payload) {
|
|
513
|
+
const listeners = Array.from(
|
|
514
|
+
this.registry.get(event) ?? /* @__PURE__ */ new Set()
|
|
515
|
+
);
|
|
516
|
+
if (listeners.length === 0) {
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
for (const listener of listeners) {
|
|
520
|
+
try {
|
|
521
|
+
listener(payload);
|
|
522
|
+
} catch (error) {
|
|
523
|
+
this.logger.warn(`Agent event listener failed for "${event}"`, {
|
|
524
|
+
event,
|
|
525
|
+
error: error instanceof Error ? error.message : String(error)
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
removeAllListeners(event) {
|
|
531
|
+
if (event) {
|
|
532
|
+
this.registry.delete(event);
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
this.registry.clear();
|
|
536
|
+
}
|
|
537
|
+
listenerCount(event) {
|
|
538
|
+
if (event) {
|
|
539
|
+
return this.registry.get(event)?.size ?? 0;
|
|
540
|
+
}
|
|
541
|
+
let total = 0;
|
|
542
|
+
for (const listeners of this.registry.values()) {
|
|
543
|
+
total += listeners.size;
|
|
544
|
+
}
|
|
545
|
+
return total;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
|
|
469
549
|
// src/base/agent.ts
|
|
470
550
|
init_tool();
|
|
471
551
|
function sanitizeId(name) {
|
|
@@ -825,6 +905,10 @@ var BaseAgent = class {
|
|
|
825
905
|
* Whether memory is enabled
|
|
826
906
|
*/
|
|
827
907
|
enableMemory;
|
|
908
|
+
/**
|
|
909
|
+
* Whether streaming is enabled
|
|
910
|
+
*/
|
|
911
|
+
enableStreaming;
|
|
828
912
|
/**
|
|
829
913
|
* Memory instance for persistent storage (null if disabled or initialization failed)
|
|
830
914
|
*/
|
|
@@ -837,6 +921,10 @@ var BaseAgent = class {
|
|
|
837
921
|
* Hook manager for lifecycle events
|
|
838
922
|
*/
|
|
839
923
|
hooks;
|
|
924
|
+
/**
|
|
925
|
+
* Event dispatcher for runtime events (notably streaming)
|
|
926
|
+
*/
|
|
927
|
+
events;
|
|
840
928
|
/**
|
|
841
929
|
* Registry of available tools
|
|
842
930
|
*/
|
|
@@ -866,12 +954,26 @@ var BaseAgent = class {
|
|
|
866
954
|
this.inputSchema = config.inputSchema;
|
|
867
955
|
this.outputSchema = config.outputSchema;
|
|
868
956
|
this.enableMemory = config.enableMemory ?? false;
|
|
957
|
+
this.enableStreaming = config.enableStreaming ?? false;
|
|
869
958
|
this.metadata = { ...config.metadata ?? {} };
|
|
870
959
|
this.hooks = new HookManager();
|
|
960
|
+
this.events = new AgentEventEmitter();
|
|
871
961
|
this.tools = /* @__PURE__ */ new Map();
|
|
872
962
|
this.baseTools = /* @__PURE__ */ new Map();
|
|
873
963
|
this.toolProviders = /* @__PURE__ */ new Set();
|
|
874
964
|
this.providerToolRegistry = /* @__PURE__ */ new Map();
|
|
965
|
+
if (config.onStreamStart) {
|
|
966
|
+
this.on(HookEvents.StreamStart, config.onStreamStart);
|
|
967
|
+
}
|
|
968
|
+
if (config.onStreamChunk) {
|
|
969
|
+
this.on(HookEvents.StreamChunk, config.onStreamChunk);
|
|
970
|
+
}
|
|
971
|
+
if (config.onStreamEnd) {
|
|
972
|
+
this.on(HookEvents.StreamEnd, config.onStreamEnd);
|
|
973
|
+
}
|
|
974
|
+
if (config.onStreamError) {
|
|
975
|
+
this.on(HookEvents.StreamError, config.onStreamError);
|
|
976
|
+
}
|
|
875
977
|
this.opperConfig = {
|
|
876
978
|
apiKey: config.opperConfig?.apiKey ?? process.env["OPPER_API_KEY"],
|
|
877
979
|
baseUrl: config.opperConfig?.baseUrl,
|
|
@@ -1053,6 +1155,35 @@ var BaseAgent = class {
|
|
|
1053
1155
|
registerHook(event, handler) {
|
|
1054
1156
|
return this.hooks.on(event, handler);
|
|
1055
1157
|
}
|
|
1158
|
+
/**
|
|
1159
|
+
* Register an event listener.
|
|
1160
|
+
*
|
|
1161
|
+
* @param event - Event name
|
|
1162
|
+
* @param listener - Listener callback
|
|
1163
|
+
* @returns Cleanup function to unregister the listener
|
|
1164
|
+
*/
|
|
1165
|
+
on(event, listener) {
|
|
1166
|
+
return this.events.on(event, listener);
|
|
1167
|
+
}
|
|
1168
|
+
/**
|
|
1169
|
+
* Register a one-time event listener that removes itself after the first call.
|
|
1170
|
+
*
|
|
1171
|
+
* @param event - Event name
|
|
1172
|
+
* @param listener - Listener callback
|
|
1173
|
+
* @returns Cleanup function (no-op once listener fires)
|
|
1174
|
+
*/
|
|
1175
|
+
once(event, listener) {
|
|
1176
|
+
return this.events.once(event, listener);
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Remove a previously registered event listener.
|
|
1180
|
+
*
|
|
1181
|
+
* @param event - Event name
|
|
1182
|
+
* @param listener - Listener callback to remove
|
|
1183
|
+
*/
|
|
1184
|
+
off(event, listener) {
|
|
1185
|
+
this.events.off(event, listener);
|
|
1186
|
+
}
|
|
1056
1187
|
/**
|
|
1057
1188
|
* Trigger a hook event with a payload.
|
|
1058
1189
|
* Swallows errors to prevent hook failures from breaking agent execution.
|
|
@@ -1067,6 +1198,15 @@ var BaseAgent = class {
|
|
|
1067
1198
|
console.warn(`Hook error for event ${event}:`, error);
|
|
1068
1199
|
}
|
|
1069
1200
|
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Emit a runtime event to listeners.
|
|
1203
|
+
*
|
|
1204
|
+
* @param event - Event name
|
|
1205
|
+
* @param payload - Event payload
|
|
1206
|
+
*/
|
|
1207
|
+
emitAgentEvent(event, payload) {
|
|
1208
|
+
this.events.emit(event, payload);
|
|
1209
|
+
}
|
|
1070
1210
|
/**
|
|
1071
1211
|
* Execute a tool with proper context, hooks, and error handling.
|
|
1072
1212
|
*
|
|
@@ -1340,7 +1480,7 @@ var ToolExecutionSummarySchema = zod.z.object({
|
|
|
1340
1480
|
|
|
1341
1481
|
// package.json
|
|
1342
1482
|
var package_default = {
|
|
1343
|
-
version: "0.
|
|
1483
|
+
version: "0.2.0"};
|
|
1344
1484
|
|
|
1345
1485
|
// src/utils/version.ts
|
|
1346
1486
|
var SDK_NAME = "@opperai/agents";
|
|
@@ -1403,7 +1543,7 @@ var OpperClient = class {
|
|
|
1403
1543
|
return this.withRetry(async () => {
|
|
1404
1544
|
const inputSchema = this.toJsonSchema(options.inputSchema);
|
|
1405
1545
|
const outputSchema = this.toJsonSchema(options.outputSchema);
|
|
1406
|
-
const
|
|
1546
|
+
const callPayload = {
|
|
1407
1547
|
name: options.name,
|
|
1408
1548
|
instructions: options.instructions,
|
|
1409
1549
|
input: options.input,
|
|
@@ -1411,7 +1551,8 @@ var OpperClient = class {
|
|
|
1411
1551
|
...outputSchema && { outputSchema },
|
|
1412
1552
|
...options.model && { model: options.model },
|
|
1413
1553
|
...options.parentSpanId && { parentSpanId: options.parentSpanId }
|
|
1414
|
-
}
|
|
1554
|
+
};
|
|
1555
|
+
const response = options.signal ? await this.client.call(callPayload, { signal: options.signal }) : await this.client.call(callPayload);
|
|
1415
1556
|
const usagePayload = extractUsage(response);
|
|
1416
1557
|
const costPayload = extractCost(response);
|
|
1417
1558
|
const usage = {
|
|
@@ -1429,6 +1570,36 @@ var OpperClient = class {
|
|
|
1429
1570
|
return result;
|
|
1430
1571
|
}, options.name);
|
|
1431
1572
|
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Stream a call to Opper with retry logic
|
|
1575
|
+
*/
|
|
1576
|
+
async stream(options) {
|
|
1577
|
+
return this.withRetry(async () => {
|
|
1578
|
+
const inputSchema = this.toJsonSchema(options.inputSchema);
|
|
1579
|
+
const outputSchema = this.toJsonSchema(options.outputSchema);
|
|
1580
|
+
const streamPayload = {
|
|
1581
|
+
name: options.name,
|
|
1582
|
+
instructions: options.instructions,
|
|
1583
|
+
input: options.input,
|
|
1584
|
+
...inputSchema && { inputSchema },
|
|
1585
|
+
...outputSchema && { outputSchema },
|
|
1586
|
+
...options.model && { model: options.model },
|
|
1587
|
+
...options.parentSpanId && { parentSpanId: options.parentSpanId }
|
|
1588
|
+
};
|
|
1589
|
+
const response = options.signal ? await this.client.stream(streamPayload, { signal: options.signal }) : await this.client.stream(streamPayload);
|
|
1590
|
+
const iterable = {
|
|
1591
|
+
async *[Symbol.asyncIterator]() {
|
|
1592
|
+
for await (const event of response.result) {
|
|
1593
|
+
yield event;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
};
|
|
1597
|
+
return {
|
|
1598
|
+
headers: response.headers,
|
|
1599
|
+
result: iterable
|
|
1600
|
+
};
|
|
1601
|
+
}, `stream:${options.name}`);
|
|
1602
|
+
}
|
|
1432
1603
|
/**
|
|
1433
1604
|
* Create a span for tracing
|
|
1434
1605
|
*/
|
|
@@ -1597,6 +1768,189 @@ var mergeSchemaDefaults = (schema, value) => {
|
|
|
1597
1768
|
return validateSchema(schema, value);
|
|
1598
1769
|
};
|
|
1599
1770
|
|
|
1771
|
+
// src/utils/streaming.ts
|
|
1772
|
+
var STREAM_ROOT_PATH = "_root";
|
|
1773
|
+
var NUMERIC_TOKEN_PATTERN = /^\d+$/;
|
|
1774
|
+
var BRACKET_TOKEN_PATTERN = /\[(\d+)\]/g;
|
|
1775
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1776
|
+
var coercePrimitive = (value) => {
|
|
1777
|
+
const trimmed = value.trim();
|
|
1778
|
+
if (trimmed.length === 0) {
|
|
1779
|
+
return value;
|
|
1780
|
+
}
|
|
1781
|
+
const lower = trimmed.toLowerCase();
|
|
1782
|
+
if (lower === "true") {
|
|
1783
|
+
return true;
|
|
1784
|
+
}
|
|
1785
|
+
if (lower === "false") {
|
|
1786
|
+
return false;
|
|
1787
|
+
}
|
|
1788
|
+
if (lower === "null") {
|
|
1789
|
+
return null;
|
|
1790
|
+
}
|
|
1791
|
+
if (/^-?\d+$/.test(trimmed)) {
|
|
1792
|
+
const intValue = Number.parseInt(trimmed, 10);
|
|
1793
|
+
return Number.isNaN(intValue) ? value : intValue;
|
|
1794
|
+
}
|
|
1795
|
+
if (/^-?\d+\.\d+$/.test(trimmed)) {
|
|
1796
|
+
const floatValue = Number.parseFloat(trimmed);
|
|
1797
|
+
return Number.isNaN(floatValue) ? value : floatValue;
|
|
1798
|
+
}
|
|
1799
|
+
return value;
|
|
1800
|
+
};
|
|
1801
|
+
var toDisplayString = (value) => {
|
|
1802
|
+
if (value === null || value === void 0) {
|
|
1803
|
+
return "";
|
|
1804
|
+
}
|
|
1805
|
+
if (typeof value === "string") {
|
|
1806
|
+
return value;
|
|
1807
|
+
}
|
|
1808
|
+
return String(value);
|
|
1809
|
+
};
|
|
1810
|
+
var parsePathSegments = (path) => {
|
|
1811
|
+
return path.replace(BRACKET_TOKEN_PATTERN, (_, index) => `.${index}`).split(".").map((segment) => segment.trim()).filter((segment) => segment.length > 0);
|
|
1812
|
+
};
|
|
1813
|
+
var setNestedValue = (target, path, value) => {
|
|
1814
|
+
const segments = parsePathSegments(path);
|
|
1815
|
+
if (segments.length === 0) {
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
let current = target;
|
|
1819
|
+
for (let i = 0; i < segments.length - 1; i++) {
|
|
1820
|
+
const segment = segments[i];
|
|
1821
|
+
if (segment === void 0) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const existing = current[segment];
|
|
1825
|
+
if (!isRecord(existing)) {
|
|
1826
|
+
const nextLevel = {};
|
|
1827
|
+
current[segment] = nextLevel;
|
|
1828
|
+
current = nextLevel;
|
|
1829
|
+
continue;
|
|
1830
|
+
}
|
|
1831
|
+
current = existing;
|
|
1832
|
+
}
|
|
1833
|
+
const lastSegment = segments[segments.length - 1];
|
|
1834
|
+
if (lastSegment === void 0) {
|
|
1835
|
+
return;
|
|
1836
|
+
}
|
|
1837
|
+
current[lastSegment] = value;
|
|
1838
|
+
};
|
|
1839
|
+
var normalizeIndexed = (value) => {
|
|
1840
|
+
if (Array.isArray(value)) {
|
|
1841
|
+
return value.map((item) => normalizeIndexed(item));
|
|
1842
|
+
}
|
|
1843
|
+
if (!isRecord(value)) {
|
|
1844
|
+
return value;
|
|
1845
|
+
}
|
|
1846
|
+
const normalizedEntries = {};
|
|
1847
|
+
for (const [key, entryValue] of Object.entries(value)) {
|
|
1848
|
+
normalizedEntries[key] = normalizeIndexed(entryValue);
|
|
1849
|
+
}
|
|
1850
|
+
const keys = Object.keys(normalizedEntries);
|
|
1851
|
+
if (keys.length > 0 && keys.every((key) => NUMERIC_TOKEN_PATTERN.test(key))) {
|
|
1852
|
+
const parsedIndices = keys.map((key) => Number.parseInt(key, 10)).filter((index) => Number.isFinite(index) && index >= 0);
|
|
1853
|
+
if (parsedIndices.length === 0) {
|
|
1854
|
+
return normalizedEntries;
|
|
1855
|
+
}
|
|
1856
|
+
const maxIndex = Math.max(...parsedIndices);
|
|
1857
|
+
const result = new Array(maxIndex + 1).fill(void 0);
|
|
1858
|
+
for (const [key, entryValue] of Object.entries(normalizedEntries)) {
|
|
1859
|
+
const index = Number.parseInt(key, 10);
|
|
1860
|
+
if (!Number.isFinite(index) || index < 0) {
|
|
1861
|
+
continue;
|
|
1862
|
+
}
|
|
1863
|
+
result[index] = entryValue;
|
|
1864
|
+
}
|
|
1865
|
+
return result.map(
|
|
1866
|
+
(item) => item === void 0 ? null : item
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1869
|
+
return normalizedEntries;
|
|
1870
|
+
};
|
|
1871
|
+
var resolveFieldValue = (path, displayBuffers, valueBuffers) => {
|
|
1872
|
+
const values = valueBuffers.get(path) ?? [];
|
|
1873
|
+
if (values.length === 0) {
|
|
1874
|
+
return displayBuffers.get(path) ?? "";
|
|
1875
|
+
}
|
|
1876
|
+
const last = values[values.length - 1];
|
|
1877
|
+
if (typeof last === "number" || typeof last === "boolean") {
|
|
1878
|
+
return last;
|
|
1879
|
+
}
|
|
1880
|
+
if (last === null) {
|
|
1881
|
+
return null;
|
|
1882
|
+
}
|
|
1883
|
+
const joined = displayBuffers.get(path) ?? values.map((value) => toDisplayString(value)).join("");
|
|
1884
|
+
return coercePrimitive(joined);
|
|
1885
|
+
};
|
|
1886
|
+
var StreamAssembler = class {
|
|
1887
|
+
displayBuffers = /* @__PURE__ */ new Map();
|
|
1888
|
+
valueBuffers = /* @__PURE__ */ new Map();
|
|
1889
|
+
schema;
|
|
1890
|
+
constructor(options = {}) {
|
|
1891
|
+
this.schema = options.schema;
|
|
1892
|
+
}
|
|
1893
|
+
feed(chunk) {
|
|
1894
|
+
const { delta } = chunk;
|
|
1895
|
+
if (delta === null || delta === void 0) {
|
|
1896
|
+
return null;
|
|
1897
|
+
}
|
|
1898
|
+
const path = chunk.jsonPath === null || chunk.jsonPath === void 0 ? STREAM_ROOT_PATH : chunk.jsonPath;
|
|
1899
|
+
const existingDisplay = this.displayBuffers.get(path) ?? "";
|
|
1900
|
+
const nextDisplay = `${existingDisplay}${toDisplayString(delta)}`;
|
|
1901
|
+
this.displayBuffers.set(path, nextDisplay);
|
|
1902
|
+
const existingValues = this.valueBuffers.get(path) ?? [];
|
|
1903
|
+
existingValues.push(delta);
|
|
1904
|
+
this.valueBuffers.set(path, existingValues);
|
|
1905
|
+
return {
|
|
1906
|
+
path,
|
|
1907
|
+
accumulated: nextDisplay,
|
|
1908
|
+
snapshot: this.snapshot()
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
snapshot() {
|
|
1912
|
+
return Object.fromEntries(this.displayBuffers.entries());
|
|
1913
|
+
}
|
|
1914
|
+
hasStructuredFields() {
|
|
1915
|
+
const keys = Array.from(this.displayBuffers.keys());
|
|
1916
|
+
return keys.some((key) => key !== STREAM_ROOT_PATH);
|
|
1917
|
+
}
|
|
1918
|
+
finalize() {
|
|
1919
|
+
if (this.displayBuffers.size === 0) {
|
|
1920
|
+
return { type: "empty" };
|
|
1921
|
+
}
|
|
1922
|
+
if (!this.hasStructuredFields()) {
|
|
1923
|
+
const root = this.displayBuffers.get(STREAM_ROOT_PATH) ?? "";
|
|
1924
|
+
return { type: "root", rootText: root };
|
|
1925
|
+
}
|
|
1926
|
+
const structured = this.reconstructStructured();
|
|
1927
|
+
let coerced = structured;
|
|
1928
|
+
if (this.schema !== void 0) {
|
|
1929
|
+
try {
|
|
1930
|
+
coerced = this.schema.parse(structured);
|
|
1931
|
+
} catch {
|
|
1932
|
+
coerced = structured;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
return { type: "structured", structured: coerced };
|
|
1936
|
+
}
|
|
1937
|
+
getFieldBuffers() {
|
|
1938
|
+
return new Map(this.displayBuffers);
|
|
1939
|
+
}
|
|
1940
|
+
reconstructStructured() {
|
|
1941
|
+
const result = {};
|
|
1942
|
+
for (const path of this.valueBuffers.keys()) {
|
|
1943
|
+
if (path === STREAM_ROOT_PATH) {
|
|
1944
|
+
continue;
|
|
1945
|
+
}
|
|
1946
|
+
const value = resolveFieldValue(path, this.displayBuffers, this.valueBuffers);
|
|
1947
|
+
setNestedValue(result, path, value);
|
|
1948
|
+
}
|
|
1949
|
+
return normalizeIndexed(result);
|
|
1950
|
+
}
|
|
1951
|
+
};
|
|
1952
|
+
var createStreamAssembler = (options) => new StreamAssembler(options);
|
|
1953
|
+
|
|
1600
1954
|
// src/core/agent.ts
|
|
1601
1955
|
var isToolSuccessResult = (value) => {
|
|
1602
1956
|
if (typeof value !== "object" || value === null) {
|
|
@@ -1723,6 +2077,9 @@ var Agent = class extends BaseAgent {
|
|
|
1723
2077
|
const spanName = "think";
|
|
1724
2078
|
this.log("Think step", { iteration: context.iteration });
|
|
1725
2079
|
await this.triggerHook(HookEvents.LlmCall, { context, callType: "think" });
|
|
2080
|
+
if (this.enableStreaming) {
|
|
2081
|
+
return this.thinkStreaming(input, context);
|
|
2082
|
+
}
|
|
1726
2083
|
try {
|
|
1727
2084
|
const instructions = this.buildThinkInstructions();
|
|
1728
2085
|
const thinkContext = await this.buildThinkContext(input, context);
|
|
@@ -1765,6 +2122,132 @@ var Agent = class extends BaseAgent {
|
|
|
1765
2122
|
);
|
|
1766
2123
|
}
|
|
1767
2124
|
}
|
|
2125
|
+
async thinkStreaming(input, context) {
|
|
2126
|
+
const spanName = "think";
|
|
2127
|
+
const instructions = this.buildThinkInstructions();
|
|
2128
|
+
const thinkContext = await this.buildThinkContext(input, context);
|
|
2129
|
+
const assembler = createStreamAssembler({
|
|
2130
|
+
schema: AgentDecisionSchema
|
|
2131
|
+
});
|
|
2132
|
+
let streamSpanId;
|
|
2133
|
+
await this.triggerHook(HookEvents.StreamStart, {
|
|
2134
|
+
context,
|
|
2135
|
+
callType: "think"
|
|
2136
|
+
});
|
|
2137
|
+
this.emitAgentEvent(HookEvents.StreamStart, {
|
|
2138
|
+
context,
|
|
2139
|
+
callType: "think"
|
|
2140
|
+
});
|
|
2141
|
+
try {
|
|
2142
|
+
const streamResponse = await this.opperClient.stream({
|
|
2143
|
+
name: spanName,
|
|
2144
|
+
instructions,
|
|
2145
|
+
input: thinkContext,
|
|
2146
|
+
outputSchema: AgentDecisionSchema,
|
|
2147
|
+
model: this.model,
|
|
2148
|
+
...context.parentSpanId && { parentSpanId: context.parentSpanId }
|
|
2149
|
+
});
|
|
2150
|
+
for await (const event of streamResponse.result) {
|
|
2151
|
+
const data = event?.data;
|
|
2152
|
+
if (!data) {
|
|
2153
|
+
continue;
|
|
2154
|
+
}
|
|
2155
|
+
if (!streamSpanId && typeof data.spanId === "string" && data.spanId) {
|
|
2156
|
+
streamSpanId = data.spanId;
|
|
2157
|
+
}
|
|
2158
|
+
const feedResult = assembler.feed({
|
|
2159
|
+
delta: data.delta,
|
|
2160
|
+
jsonPath: data.jsonPath
|
|
2161
|
+
});
|
|
2162
|
+
if (!feedResult) {
|
|
2163
|
+
continue;
|
|
2164
|
+
}
|
|
2165
|
+
const chunkPayload = {
|
|
2166
|
+
context,
|
|
2167
|
+
callType: "think",
|
|
2168
|
+
chunkData: {
|
|
2169
|
+
delta: data.delta,
|
|
2170
|
+
jsonPath: data.jsonPath ?? null,
|
|
2171
|
+
chunkType: data.chunkType ?? null
|
|
2172
|
+
},
|
|
2173
|
+
accumulated: feedResult.accumulated,
|
|
2174
|
+
fieldBuffers: feedResult.snapshot
|
|
2175
|
+
};
|
|
2176
|
+
await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
|
|
2177
|
+
this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
|
|
2178
|
+
}
|
|
2179
|
+
const fieldBuffers = assembler.snapshot();
|
|
2180
|
+
const endPayload = {
|
|
2181
|
+
context,
|
|
2182
|
+
callType: "think",
|
|
2183
|
+
fieldBuffers
|
|
2184
|
+
};
|
|
2185
|
+
await this.triggerHook(HookEvents.StreamEnd, endPayload);
|
|
2186
|
+
this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
|
|
2187
|
+
const finalize = assembler.finalize();
|
|
2188
|
+
let decision;
|
|
2189
|
+
if (finalize.type === "structured" && finalize.structured) {
|
|
2190
|
+
decision = AgentDecisionSchema.parse(
|
|
2191
|
+
finalize.structured
|
|
2192
|
+
);
|
|
2193
|
+
} else {
|
|
2194
|
+
decision = AgentDecisionSchema.parse({
|
|
2195
|
+
reasoning: finalize.type === "root" ? finalize.rootText ?? "" : ""
|
|
2196
|
+
});
|
|
2197
|
+
}
|
|
2198
|
+
const usageTracked = await this.trackStreamingUsageBySpan(
|
|
2199
|
+
context,
|
|
2200
|
+
streamSpanId
|
|
2201
|
+
);
|
|
2202
|
+
if (!usageTracked) {
|
|
2203
|
+
context.updateUsage({
|
|
2204
|
+
requests: 1,
|
|
2205
|
+
inputTokens: 0,
|
|
2206
|
+
outputTokens: 0,
|
|
2207
|
+
totalTokens: 0,
|
|
2208
|
+
cost: { generation: 0, platform: 0, total: 0 }
|
|
2209
|
+
});
|
|
2210
|
+
}
|
|
2211
|
+
await this.triggerHook(HookEvents.LlmResponse, {
|
|
2212
|
+
context,
|
|
2213
|
+
callType: "think",
|
|
2214
|
+
response: streamResponse,
|
|
2215
|
+
parsed: decision
|
|
2216
|
+
});
|
|
2217
|
+
await this.triggerHook(HookEvents.ThinkEnd, {
|
|
2218
|
+
context,
|
|
2219
|
+
thought: { reasoning: decision.reasoning }
|
|
2220
|
+
});
|
|
2221
|
+
this.log("Think result", {
|
|
2222
|
+
reasoning: decision.reasoning,
|
|
2223
|
+
toolCalls: decision.toolCalls.length,
|
|
2224
|
+
memoryReads: decision.memoryReads?.length ?? 0,
|
|
2225
|
+
memoryWrites: Object.keys(decision.memoryUpdates ?? {}).length
|
|
2226
|
+
});
|
|
2227
|
+
const resultPayload = {
|
|
2228
|
+
decision
|
|
2229
|
+
};
|
|
2230
|
+
if (streamSpanId) {
|
|
2231
|
+
resultPayload.spanId = streamSpanId;
|
|
2232
|
+
}
|
|
2233
|
+
return resultPayload;
|
|
2234
|
+
} catch (error) {
|
|
2235
|
+
await this.triggerHook(HookEvents.StreamError, {
|
|
2236
|
+
context,
|
|
2237
|
+
callType: "think",
|
|
2238
|
+
error
|
|
2239
|
+
});
|
|
2240
|
+
this.emitAgentEvent(HookEvents.StreamError, {
|
|
2241
|
+
context,
|
|
2242
|
+
callType: "think",
|
|
2243
|
+
error
|
|
2244
|
+
});
|
|
2245
|
+
this.logger.error("Think step failed", error);
|
|
2246
|
+
throw new Error(
|
|
2247
|
+
`Think step failed: ${error instanceof Error ? error.message : String(error)}`
|
|
2248
|
+
);
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
1768
2251
|
/**
|
|
1769
2252
|
* Build static instructions for the think step
|
|
1770
2253
|
*/
|
|
@@ -2078,6 +2561,13 @@ The memory you write persists across all process() calls on this agent.`;
|
|
|
2078
2561
|
};
|
|
2079
2562
|
const instructions = `Generate the final result based on the execution history.
|
|
2080
2563
|
Follow any instructions provided for formatting and style.`;
|
|
2564
|
+
if (this.enableStreaming) {
|
|
2565
|
+
return this.generateFinalResultStreaming(
|
|
2566
|
+
context,
|
|
2567
|
+
finalContext,
|
|
2568
|
+
instructions
|
|
2569
|
+
);
|
|
2570
|
+
}
|
|
2081
2571
|
try {
|
|
2082
2572
|
const callOptions = {
|
|
2083
2573
|
name: "generate_final_result",
|
|
@@ -2113,6 +2603,170 @@ Follow any instructions provided for formatting and style.`;
|
|
|
2113
2603
|
);
|
|
2114
2604
|
}
|
|
2115
2605
|
}
|
|
2606
|
+
async generateFinalResultStreaming(context, finalContext, instructions) {
|
|
2607
|
+
const assembler = createStreamAssembler(
|
|
2608
|
+
this.outputSchema ? { schema: this.outputSchema } : void 0
|
|
2609
|
+
);
|
|
2610
|
+
let streamSpanId;
|
|
2611
|
+
await this.triggerHook(HookEvents.StreamStart, {
|
|
2612
|
+
context,
|
|
2613
|
+
callType: "final_result"
|
|
2614
|
+
});
|
|
2615
|
+
this.emitAgentEvent(HookEvents.StreamStart, {
|
|
2616
|
+
context,
|
|
2617
|
+
callType: "final_result"
|
|
2618
|
+
});
|
|
2619
|
+
try {
|
|
2620
|
+
const streamResponse = await this.opperClient.stream({
|
|
2621
|
+
name: "generate_final_result",
|
|
2622
|
+
instructions,
|
|
2623
|
+
input: finalContext,
|
|
2624
|
+
model: this.model,
|
|
2625
|
+
...context.parentSpanId && { parentSpanId: context.parentSpanId },
|
|
2626
|
+
...this.outputSchema && { outputSchema: this.outputSchema }
|
|
2627
|
+
});
|
|
2628
|
+
for await (const event of streamResponse.result) {
|
|
2629
|
+
const data = event?.data;
|
|
2630
|
+
if (!data) {
|
|
2631
|
+
continue;
|
|
2632
|
+
}
|
|
2633
|
+
if (!streamSpanId && typeof data.spanId === "string" && data.spanId) {
|
|
2634
|
+
streamSpanId = data.spanId;
|
|
2635
|
+
}
|
|
2636
|
+
const feedResult = assembler.feed({
|
|
2637
|
+
delta: data.delta,
|
|
2638
|
+
jsonPath: data.jsonPath
|
|
2639
|
+
});
|
|
2640
|
+
if (!feedResult) {
|
|
2641
|
+
continue;
|
|
2642
|
+
}
|
|
2643
|
+
const chunkPayload = {
|
|
2644
|
+
context,
|
|
2645
|
+
callType: "final_result",
|
|
2646
|
+
chunkData: {
|
|
2647
|
+
delta: data.delta,
|
|
2648
|
+
jsonPath: data.jsonPath ?? null,
|
|
2649
|
+
chunkType: data.chunkType ?? null
|
|
2650
|
+
},
|
|
2651
|
+
accumulated: feedResult.accumulated,
|
|
2652
|
+
fieldBuffers: feedResult.snapshot
|
|
2653
|
+
};
|
|
2654
|
+
await this.triggerHook(HookEvents.StreamChunk, chunkPayload);
|
|
2655
|
+
this.emitAgentEvent(HookEvents.StreamChunk, chunkPayload);
|
|
2656
|
+
}
|
|
2657
|
+
const fieldBuffers = assembler.snapshot();
|
|
2658
|
+
const endPayload = {
|
|
2659
|
+
context,
|
|
2660
|
+
callType: "final_result",
|
|
2661
|
+
fieldBuffers
|
|
2662
|
+
};
|
|
2663
|
+
await this.triggerHook(HookEvents.StreamEnd, endPayload);
|
|
2664
|
+
this.emitAgentEvent(HookEvents.StreamEnd, endPayload);
|
|
2665
|
+
const finalize = assembler.finalize();
|
|
2666
|
+
let result;
|
|
2667
|
+
if (this.outputSchema) {
|
|
2668
|
+
if (finalize.type !== "structured" || finalize.structured === void 0) {
|
|
2669
|
+
throw new Error(
|
|
2670
|
+
"Streaming response did not provide structured data for the configured output schema."
|
|
2671
|
+
);
|
|
2672
|
+
}
|
|
2673
|
+
result = this.outputSchema.parse(
|
|
2674
|
+
finalize.structured
|
|
2675
|
+
);
|
|
2676
|
+
} else if (finalize.type === "root") {
|
|
2677
|
+
result = finalize.rootText ?? "";
|
|
2678
|
+
} else if (finalize.type === "structured" && finalize.structured) {
|
|
2679
|
+
result = JSON.stringify(finalize.structured);
|
|
2680
|
+
} else {
|
|
2681
|
+
result = "";
|
|
2682
|
+
}
|
|
2683
|
+
const usageTracked = await this.trackStreamingUsageBySpan(
|
|
2684
|
+
context,
|
|
2685
|
+
streamSpanId
|
|
2686
|
+
);
|
|
2687
|
+
if (!usageTracked) {
|
|
2688
|
+
context.updateUsage({
|
|
2689
|
+
requests: 1,
|
|
2690
|
+
inputTokens: 0,
|
|
2691
|
+
outputTokens: 0,
|
|
2692
|
+
totalTokens: 0,
|
|
2693
|
+
cost: { generation: 0, platform: 0, total: 0 }
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
await this.triggerHook(HookEvents.LlmResponse, {
|
|
2697
|
+
context,
|
|
2698
|
+
callType: "final_result",
|
|
2699
|
+
response: streamResponse,
|
|
2700
|
+
parsed: result
|
|
2701
|
+
});
|
|
2702
|
+
this.log(
|
|
2703
|
+
this.outputSchema ? "Final result generated (streaming, schema-validated)" : "Final result generated (streaming)"
|
|
2704
|
+
);
|
|
2705
|
+
return result;
|
|
2706
|
+
} catch (error) {
|
|
2707
|
+
await this.triggerHook(HookEvents.StreamError, {
|
|
2708
|
+
context,
|
|
2709
|
+
callType: "final_result",
|
|
2710
|
+
error
|
|
2711
|
+
});
|
|
2712
|
+
this.emitAgentEvent(HookEvents.StreamError, {
|
|
2713
|
+
context,
|
|
2714
|
+
callType: "final_result",
|
|
2715
|
+
error
|
|
2716
|
+
});
|
|
2717
|
+
this.logger.error("Failed to generate final result", error);
|
|
2718
|
+
throw new Error(
|
|
2719
|
+
`Failed to generate final result: ${error instanceof Error ? error.message : String(error)}`
|
|
2720
|
+
);
|
|
2721
|
+
}
|
|
2722
|
+
}
|
|
2723
|
+
async trackStreamingUsageBySpan(context, spanId) {
|
|
2724
|
+
if (!spanId) {
|
|
2725
|
+
return false;
|
|
2726
|
+
}
|
|
2727
|
+
try {
|
|
2728
|
+
const span = await this.opperClient.getClient().spans.get(spanId);
|
|
2729
|
+
const traceId = span?.traceId ?? span?.trace_id;
|
|
2730
|
+
if (!traceId) {
|
|
2731
|
+
return false;
|
|
2732
|
+
}
|
|
2733
|
+
const trace = await this.opperClient.getClient().traces.get(traceId);
|
|
2734
|
+
const spans = trace?.spans;
|
|
2735
|
+
if (!Array.isArray(spans)) {
|
|
2736
|
+
return false;
|
|
2737
|
+
}
|
|
2738
|
+
for (const entry of spans) {
|
|
2739
|
+
const entryId = entry?.id ?? entry["id"];
|
|
2740
|
+
if (entryId !== spanId) {
|
|
2741
|
+
continue;
|
|
2742
|
+
}
|
|
2743
|
+
const data = entry?.data;
|
|
2744
|
+
if (!data) {
|
|
2745
|
+
continue;
|
|
2746
|
+
}
|
|
2747
|
+
const record = data;
|
|
2748
|
+
const primaryTotal = record["totalTokens"];
|
|
2749
|
+
const fallbackTotal = record["total_tokens"];
|
|
2750
|
+
const totalTokensRaw = typeof primaryTotal === "number" && Number.isFinite(primaryTotal) ? primaryTotal : typeof fallbackTotal === "number" && Number.isFinite(fallbackTotal) ? fallbackTotal : void 0;
|
|
2751
|
+
if (totalTokensRaw !== void 0) {
|
|
2752
|
+
context.updateUsage({
|
|
2753
|
+
requests: 1,
|
|
2754
|
+
inputTokens: 0,
|
|
2755
|
+
outputTokens: 0,
|
|
2756
|
+
totalTokens: totalTokensRaw,
|
|
2757
|
+
cost: { generation: 0, platform: 0, total: 0 }
|
|
2758
|
+
});
|
|
2759
|
+
return true;
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
} catch (error) {
|
|
2763
|
+
this.logger.warn("Could not fetch streaming usage", {
|
|
2764
|
+
spanId,
|
|
2765
|
+
error: error instanceof Error ? error.message : String(error)
|
|
2766
|
+
});
|
|
2767
|
+
}
|
|
2768
|
+
return false;
|
|
2769
|
+
}
|
|
2116
2770
|
/**
|
|
2117
2771
|
* Log helper
|
|
2118
2772
|
*/
|
|
@@ -2329,7 +2983,7 @@ var createMCPServerConfig = MCPconfig;
|
|
|
2329
2983
|
|
|
2330
2984
|
// src/mcp/provider.ts
|
|
2331
2985
|
init_tool();
|
|
2332
|
-
var
|
|
2986
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null;
|
|
2333
2987
|
var MCPToolProvider = class {
|
|
2334
2988
|
configs;
|
|
2335
2989
|
namePrefix;
|
|
@@ -2420,7 +3074,7 @@ var MCPToolProvider = class {
|
|
|
2420
3074
|
},
|
|
2421
3075
|
execute: async (input, context) => {
|
|
2422
3076
|
const startedAt = Date.now();
|
|
2423
|
-
const args =
|
|
3077
|
+
const args = isRecord2(input) ? input : input === void 0 ? {} : { value: input };
|
|
2424
3078
|
try {
|
|
2425
3079
|
const result = await client.callTool(mcpTool.name, args);
|
|
2426
3080
|
return exports.ToolResultFactory.success(toolName, result, {
|
|
@@ -2880,6 +3534,8 @@ var ToolRunner = class {
|
|
|
2880
3534
|
|
|
2881
3535
|
exports.Agent = Agent;
|
|
2882
3536
|
exports.AgentDecisionSchema = AgentDecisionSchema;
|
|
3537
|
+
exports.AgentEventEmitter = AgentEventEmitter;
|
|
3538
|
+
exports.AgentEvents = AgentEvents;
|
|
2883
3539
|
exports.BaseAgent = BaseAgent;
|
|
2884
3540
|
exports.ConsoleLogger = ConsoleLogger;
|
|
2885
3541
|
exports.DEFAULT_MODEL = DEFAULT_MODEL;
|
|
@@ -2896,8 +3552,10 @@ exports.MemoryEntryMetadataSchema = MemoryEntryMetadataSchema;
|
|
|
2896
3552
|
exports.MemoryEntrySchema = MemoryEntrySchema;
|
|
2897
3553
|
exports.MemoryUpdateSchema = MemoryUpdateSchema;
|
|
2898
3554
|
exports.OpperClient = OpperClient;
|
|
3555
|
+
exports.STREAM_ROOT_PATH = STREAM_ROOT_PATH;
|
|
2899
3556
|
exports.SchemaValidationError = SchemaValidationError;
|
|
2900
3557
|
exports.SilentLogger = SilentLogger;
|
|
3558
|
+
exports.StreamAssembler = StreamAssembler;
|
|
2901
3559
|
exports.ThoughtSchema = ThoughtSchema;
|
|
2902
3560
|
exports.ToolCallSchema = ToolCallSchema;
|
|
2903
3561
|
exports.ToolExecutionSummarySchema = ToolExecutionSummarySchema;
|
|
@@ -2907,6 +3565,7 @@ exports.createHookManager = createHookManager;
|
|
|
2907
3565
|
exports.createInMemoryStore = createInMemoryStore;
|
|
2908
3566
|
exports.createMCPServerConfig = createMCPServerConfig;
|
|
2909
3567
|
exports.createOpperClient = createOpperClient;
|
|
3568
|
+
exports.createStreamAssembler = createStreamAssembler;
|
|
2910
3569
|
exports.extractTools = extractTools;
|
|
2911
3570
|
exports.generateAgentFlowDiagram = generateAgentFlowDiagram;
|
|
2912
3571
|
exports.getDefaultLogger = getDefaultLogger;
|