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