@opperai/agents 0.2.0 → 0.3.0-beta.1

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.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from 'crypto';
2
+ import * as zod from 'zod';
2
3
  import { z } from 'zod';
3
4
  import { promises } from 'fs';
4
5
  import { Opper } from 'opperai';
@@ -570,8 +571,11 @@ function getSchemaName(schema) {
570
571
  return schemaAny._def.description;
571
572
  }
572
573
  const typeName = schemaAny._def?.typeName;
573
- if (typeName === "ZodObject" && schemaAny._def) {
574
- const shape = schemaAny._def.shape?.();
574
+ const type = schemaAny._def?.type;
575
+ const isObject = typeName === "ZodObject" || type === "object";
576
+ if (isObject && schemaAny._def) {
577
+ const shapeRaw = schemaAny._def.shape;
578
+ const shape = typeof shapeRaw === "function" ? shapeRaw() : shapeRaw;
575
579
  if (shape && typeof shape === "object") {
576
580
  const keys = Object.keys(shape);
577
581
  if (keys.length > 0) {
@@ -584,6 +588,9 @@ function getSchemaName(schema) {
584
588
  if (typeName) {
585
589
  return typeName.replace("Zod", "").replace("Type", "");
586
590
  }
591
+ if (type) {
592
+ return type.charAt(0).toUpperCase() + type.slice(1);
593
+ }
587
594
  return "Any";
588
595
  } catch {
589
596
  return "Any";
@@ -595,12 +602,15 @@ function extractParameters(schema) {
595
602
  }
596
603
  try {
597
604
  const schemaAny = schema;
598
- if (schemaAny._def?.typeName === "ZodObject") {
599
- const shape = schemaAny._def.shape?.();
605
+ const isObject = schemaAny._def?.typeName === "ZodObject" || schemaAny._def?.type === "object";
606
+ if (isObject) {
607
+ const shapeRaw = schemaAny._def?.shape;
608
+ const shape = typeof shapeRaw === "function" ? shapeRaw() : shapeRaw;
600
609
  if (shape && typeof shape === "object") {
601
610
  const params = [];
602
611
  for (const [key, value] of Object.entries(shape)) {
603
- const fieldType = value?._def?.typeName;
612
+ const valueAny = value;
613
+ const fieldType = valueAny._def?.typeName || valueAny.def?.type || valueAny.type;
604
614
  if (fieldType) {
605
615
  const cleanType = fieldType.replace("Zod", "").toLowerCase();
606
616
  params.push(`${key}: ${cleanType}`);
@@ -943,6 +953,28 @@ var BaseAgent = class {
943
953
  * Opper client configuration
944
954
  */
945
955
  opperConfig;
956
+ /**
957
+ * Creates a new BaseAgent instance
958
+ *
959
+ * @param config - Agent configuration object
960
+ * @param config.name - Unique name identifying this agent (required)
961
+ * @param config.description - Human-readable description of the agent's purpose
962
+ * @param config.instructions - System instructions guiding agent behavior
963
+ * @param config.tools - Array of tools or tool providers available to the agent
964
+ * @param config.maxIterations - Maximum iterations before terminating the agent loop (default: 25)
965
+ * @param config.model - Model identifier(s). Single model or array for fallback (default: "gcp/gemini-flash-latest")
966
+ * @param config.inputSchema - Zod schema for input validation
967
+ * @param config.outputSchema - Zod schema for output validation
968
+ * @param config.enableStreaming - Enable Opper streaming APIs for LLM calls (default: false)
969
+ * @param config.enableMemory - Enable memory subsystem (default: false)
970
+ * @param config.memory - Custom memory implementation (defaults to InMemoryStore if enableMemory is true)
971
+ * @param config.metadata - Additional metadata for the agent
972
+ * @param config.opperConfig - Opper API configuration containing apiKey and baseUrl
973
+ * @param config.onStreamStart - Handler invoked when a streaming call starts
974
+ * @param config.onStreamChunk - Handler invoked for each streaming chunk
975
+ * @param config.onStreamEnd - Handler invoked when a streaming call ends
976
+ * @param config.onStreamError - Handler invoked when streaming encounters an error
977
+ */
946
978
  constructor(config) {
947
979
  this.name = config.name;
948
980
  this.description = config.description;
@@ -1406,7 +1438,7 @@ var ThoughtSchema = z.object({
1406
1438
  */
1407
1439
  confidence: z.number().min(0).max(1).optional(),
1408
1440
  /**
1409
- * Additional metadata
1441
+ * Additional metadata (key-value pairs)
1410
1442
  */
1411
1443
  metadata: z.record(z.string(), z.unknown()).optional()
1412
1444
  });
@@ -1443,6 +1475,10 @@ var AgentDecisionSchema = z.object({
1443
1475
  * Agent's internal reasoning
1444
1476
  */
1445
1477
  reasoning: z.string(),
1478
+ /**
1479
+ * Status message for the user (e.g., "Searching for information...", "Processing results...")
1480
+ */
1481
+ userMessage: z.string().default("Working on it..."),
1446
1482
  /**
1447
1483
  * Tool calls to execute (if any)
1448
1484
  * Empty array signals task completion
@@ -1455,8 +1491,34 @@ var AgentDecisionSchema = z.object({
1455
1491
  /**
1456
1492
  * Memory entries to write/update (key -> payload)
1457
1493
  */
1458
- memoryUpdates: z.record(MemoryUpdateSchema).default({})
1494
+ memoryUpdates: z.record(z.string(), MemoryUpdateSchema).default({}),
1495
+ /**
1496
+ * Whether the task is complete and finalResult is available
1497
+ * (single LLM call pattern)
1498
+ */
1499
+ isComplete: z.boolean().default(false),
1500
+ /**
1501
+ * The final result when isComplete=true
1502
+ * Should match outputSchema if specified
1503
+ */
1504
+ finalResult: z.unknown().optional()
1459
1505
  });
1506
+ function createAgentDecisionWithOutputSchema(outputSchema) {
1507
+ if (!outputSchema) {
1508
+ return AgentDecisionSchema;
1509
+ }
1510
+ const finalResultSchema = outputSchema.optional();
1511
+ const dynamicSchema = z.object({
1512
+ reasoning: z.string(),
1513
+ userMessage: z.string().default("Working on it..."),
1514
+ toolCalls: z.array(ToolCallSchema).default([]),
1515
+ memoryReads: z.array(z.string()).default([]),
1516
+ memoryUpdates: z.record(z.string(), MemoryUpdateSchema).default({}),
1517
+ isComplete: z.boolean().default(false),
1518
+ finalResult: finalResultSchema
1519
+ });
1520
+ return dynamicSchema;
1521
+ }
1460
1522
  var ToolExecutionSummarySchema = z.object({
1461
1523
  /**
1462
1524
  * Tool name
@@ -1475,10 +1537,60 @@ var ToolExecutionSummarySchema = z.object({
1475
1537
  */
1476
1538
  error: z.string().optional()
1477
1539
  });
1540
+ var hasNativeToJSONSchema = typeof zod.toJSONSchema === "function";
1541
+ function zodSchemaToJsonSchema(schema) {
1542
+ if (hasNativeToJSONSchema) {
1543
+ try {
1544
+ const toJSONSchema2 = zod.toJSONSchema;
1545
+ const result = toJSONSchema2(schema);
1546
+ return result;
1547
+ } catch {
1548
+ }
1549
+ }
1550
+ return zodToJsonSchema(schema);
1551
+ }
1552
+ var SchemaValidationError = class extends Error {
1553
+ issues;
1554
+ constructor(message, issues) {
1555
+ super(message);
1556
+ this.name = "SchemaValidationError";
1557
+ this.issues = issues;
1558
+ }
1559
+ };
1560
+ var validateSchema = (schema, value, options = {}) => {
1561
+ const result = schema.safeParse(value);
1562
+ if (!result.success) {
1563
+ throw new SchemaValidationError(
1564
+ options.message ?? "Schema validation failed",
1565
+ result.error.issues
1566
+ );
1567
+ }
1568
+ return result.data;
1569
+ };
1570
+ var isSchemaValid = (schema, value) => {
1571
+ return schema.safeParse(value).success;
1572
+ };
1573
+ var schemaToJson = (schema, options = {}) => {
1574
+ if (hasNativeToJSONSchema) {
1575
+ return zodSchemaToJsonSchema(schema);
1576
+ }
1577
+ return zodToJsonSchema(schema, options);
1578
+ };
1579
+ var getSchemaDefault = (schema) => {
1580
+ const result = schema.safeParse(void 0);
1581
+ return result.success ? result.data : void 0;
1582
+ };
1583
+ var mergeSchemaDefaults = (schema, value) => {
1584
+ const defaults = getSchemaDefault(schema);
1585
+ if (defaults && typeof defaults === "object") {
1586
+ return validateSchema(schema, { ...defaults, ...value });
1587
+ }
1588
+ return validateSchema(schema, value);
1589
+ };
1478
1590
 
1479
1591
  // package.json
1480
1592
  var package_default = {
1481
- version: "0.2.0"};
1593
+ version: "0.3.0-beta.1"};
1482
1594
 
1483
1595
  // src/utils/version.ts
1484
1596
  var SDK_NAME = "@opperai/agents";
@@ -1606,7 +1718,8 @@ var OpperClient = class {
1606
1718
  const span = await this.client.spans.create({
1607
1719
  name: options.name,
1608
1720
  ...options.input !== void 0 && { input: options.input },
1609
- ...options.parentSpanId && { parentId: options.parentSpanId }
1721
+ ...options.parentSpanId && { parentId: options.parentSpanId },
1722
+ ...options.type && { type: options.type }
1610
1723
  });
1611
1724
  return {
1612
1725
  id: span.id,
@@ -1623,7 +1736,11 @@ var OpperClient = class {
1623
1736
  const serializedOutput = output !== void 0 && output !== null ? typeof output === "object" ? JSON.stringify(output) : String(output) : void 0;
1624
1737
  await this.client.spans.update(spanId, {
1625
1738
  ...serializedOutput !== void 0 && { output: serializedOutput },
1626
- ...options?.error && { error: options.error }
1739
+ ...options?.error && { error: options.error },
1740
+ ...options?.startTime && { startTime: options.startTime },
1741
+ ...options?.endTime && { endTime: options.endTime },
1742
+ ...options?.meta && { meta: options.meta },
1743
+ ...options?.name && { name: options.name }
1627
1744
  });
1628
1745
  }, `update-span:${spanId}`);
1629
1746
  }
@@ -1704,7 +1821,7 @@ var OpperClient = class {
1704
1821
  }
1705
1822
  if (isZodSchema(schema)) {
1706
1823
  try {
1707
- return zodToJsonSchema(schema);
1824
+ return zodSchemaToJsonSchema(schema);
1708
1825
  } catch (error) {
1709
1826
  this.logger.warn("Failed to convert Zod schema to JSON Schema", {
1710
1827
  error: error instanceof Error ? error.message : String(error)
@@ -1730,41 +1847,6 @@ var OpperClient = class {
1730
1847
  function createOpperClient(apiKey, options) {
1731
1848
  return new OpperClient(apiKey, options);
1732
1849
  }
1733
- var SchemaValidationError = class extends Error {
1734
- issues;
1735
- constructor(message, issues) {
1736
- super(message);
1737
- this.name = "SchemaValidationError";
1738
- this.issues = issues;
1739
- }
1740
- };
1741
- var validateSchema = (schema, value, options = {}) => {
1742
- const result = schema.safeParse(value);
1743
- if (!result.success) {
1744
- throw new SchemaValidationError(
1745
- options.message ?? "Schema validation failed",
1746
- result.error.issues
1747
- );
1748
- }
1749
- return result.data;
1750
- };
1751
- var isSchemaValid = (schema, value) => {
1752
- return schema.safeParse(value).success;
1753
- };
1754
- var schemaToJson = (schema, options = {}) => {
1755
- return zodToJsonSchema(schema, options);
1756
- };
1757
- var getSchemaDefault = (schema) => {
1758
- const result = schema.safeParse(void 0);
1759
- return result.success ? result.data : void 0;
1760
- };
1761
- var mergeSchemaDefaults = (schema, value) => {
1762
- const defaults = getSchemaDefault(schema);
1763
- if (defaults && typeof defaults === "object") {
1764
- return validateSchema(schema, { ...defaults, ...value });
1765
- }
1766
- return validateSchema(schema, value);
1767
- };
1768
1850
 
1769
1851
  // src/utils/streaming.ts
1770
1852
  var STREAM_ROOT_PATH = "_root";
@@ -1941,7 +2023,11 @@ var StreamAssembler = class {
1941
2023
  if (path === STREAM_ROOT_PATH) {
1942
2024
  continue;
1943
2025
  }
1944
- const value = resolveFieldValue(path, this.displayBuffers, this.valueBuffers);
2026
+ const value = resolveFieldValue(
2027
+ path,
2028
+ this.displayBuffers,
2029
+ this.valueBuffers
2030
+ );
1945
2031
  setNestedValue(result, path, value);
1946
2032
  }
1947
2033
  return normalizeIndexed(result);
@@ -1961,6 +2047,31 @@ var Agent = class extends BaseAgent {
1961
2047
  opperClient;
1962
2048
  logger;
1963
2049
  verbose;
2050
+ /**
2051
+ * Creates a new Agent instance
2052
+ *
2053
+ * @param config - Agent configuration object
2054
+ * @param config.name - Unique name identifying this agent (required)
2055
+ * @param config.description - Human-readable description of the agent's purpose
2056
+ * @param config.instructions - System instructions guiding agent behavior
2057
+ * @param config.tools - Array of tools or tool providers available to the agent
2058
+ * @param config.maxIterations - Maximum iterations before terminating (default: 25)
2059
+ * @param config.model - Model identifier(s) as string or array for fallback (default: "gcp/gemini-flash-latest")
2060
+ * @param config.inputSchema - Zod schema for input validation
2061
+ * @param config.outputSchema - Zod schema for output validation
2062
+ * @param config.enableStreaming - Enable streaming for LLM calls (default: false)
2063
+ * @param config.enableMemory - Enable memory subsystem (default: false)
2064
+ * @param config.memory - Custom memory implementation (defaults to InMemoryStore if enableMemory is true)
2065
+ * @param config.metadata - Additional metadata for the agent
2066
+ * @param config.opperConfig - Opper API configuration (apiKey, baseUrl)
2067
+ * @param config.opperClient - Custom Opper client instance (for testing or custom configuration)
2068
+ * @param config.logger - Logger instance for debugging
2069
+ * @param config.verbose - Enable verbose logging (default: false)
2070
+ * @param config.onStreamStart - Handler invoked when streaming starts
2071
+ * @param config.onStreamChunk - Handler invoked for each streaming chunk
2072
+ * @param config.onStreamEnd - Handler invoked when streaming ends
2073
+ * @param config.onStreamError - Handler invoked on streaming errors
2074
+ */
1964
2075
  constructor(config) {
1965
2076
  super(config);
1966
2077
  this.logger = config.logger ?? getDefaultLogger();
@@ -1996,6 +2107,7 @@ var Agent = class extends BaseAgent {
1996
2107
  maxIterations: this.maxIterations,
1997
2108
  tools: Array.from(this.tools.keys())
1998
2109
  });
2110
+ const executionStartTime = /* @__PURE__ */ new Date();
1999
2111
  const parentSpan = await this.opperClient.createSpan({
2000
2112
  name: `${this.name}_execution`,
2001
2113
  input: this.serializeInput(input),
@@ -2015,6 +2127,48 @@ var Agent = class extends BaseAgent {
2015
2127
  input,
2016
2128
  context
2017
2129
  );
2130
+ if (decision.isComplete && decision.finalResult !== void 0) {
2131
+ this.log("Task completed with final result in single call", {
2132
+ iteration: currentIteration
2133
+ });
2134
+ await this.handleMemoryActions(decision, context, thinkSpanId);
2135
+ let finalResult;
2136
+ if (this.outputSchema) {
2137
+ const parseResult = this.outputSchema.safeParse(
2138
+ decision.finalResult
2139
+ );
2140
+ if (parseResult.success) {
2141
+ finalResult = parseResult.data;
2142
+ } else {
2143
+ this.logger.warn(
2144
+ "Final result validation against output schema failed, falling back to generate_final_result",
2145
+ { error: parseResult.error.message }
2146
+ );
2147
+ break;
2148
+ }
2149
+ } else {
2150
+ const rawResult = decision.finalResult;
2151
+ if (typeof rawResult === "string") {
2152
+ finalResult = rawResult;
2153
+ } else if (rawResult === null || rawResult === void 0) {
2154
+ finalResult = "";
2155
+ } else if (typeof rawResult === "object") {
2156
+ finalResult = JSON.stringify(rawResult);
2157
+ } else {
2158
+ finalResult = String(rawResult);
2159
+ }
2160
+ }
2161
+ const executionEndTime2 = /* @__PURE__ */ new Date();
2162
+ await this.opperClient.updateSpan(parentSpan.id, finalResult, {
2163
+ startTime: executionStartTime,
2164
+ endTime: executionEndTime2,
2165
+ meta: {
2166
+ durationMs: executionEndTime2.getTime() - executionStartTime.getTime()
2167
+ }
2168
+ });
2169
+ await this.triggerHook(HookEvents.LoopEnd, { context });
2170
+ return finalResult;
2171
+ }
2018
2172
  const memoryResults = await this.handleMemoryActions(
2019
2173
  decision,
2020
2174
  context,
@@ -2024,7 +2178,7 @@ var Agent = class extends BaseAgent {
2024
2178
  const toolResults = await this.executeToolCalls(
2025
2179
  decision,
2026
2180
  context,
2027
- thinkSpanId
2181
+ context.parentSpanId ?? void 0
2028
2182
  );
2029
2183
  const combinedResults = [...memoryResults, ...toolResults];
2030
2184
  const newToolCalls = context.toolCalls.slice(toolCallStartIndex);
@@ -2059,11 +2213,24 @@ var Agent = class extends BaseAgent {
2059
2213
  );
2060
2214
  }
2061
2215
  const result = await this.generateFinalResult(input, context);
2062
- await this.opperClient.updateSpan(parentSpan.id, result);
2216
+ const executionEndTime = /* @__PURE__ */ new Date();
2217
+ await this.opperClient.updateSpan(parentSpan.id, result, {
2218
+ startTime: executionStartTime,
2219
+ endTime: executionEndTime,
2220
+ meta: {
2221
+ durationMs: executionEndTime.getTime() - executionStartTime.getTime()
2222
+ }
2223
+ });
2063
2224
  return result;
2064
2225
  } catch (error) {
2226
+ const executionEndTime = /* @__PURE__ */ new Date();
2065
2227
  await this.opperClient.updateSpan(parentSpan.id, void 0, {
2066
- error: error instanceof Error ? error.message : String(error)
2228
+ error: error instanceof Error ? error.message : String(error),
2229
+ startTime: executionStartTime,
2230
+ endTime: executionEndTime,
2231
+ meta: {
2232
+ durationMs: executionEndTime.getTime() - executionStartTime.getTime()
2233
+ }
2067
2234
  });
2068
2235
  throw error;
2069
2236
  }
@@ -2072,11 +2239,15 @@ var Agent = class extends BaseAgent {
2072
2239
  * Think step: Call LLM to decide next action
2073
2240
  */
2074
2241
  async think(input, context) {
2075
- const spanName = "think";
2242
+ const sanitizedName = this.name.toLowerCase().replace(/[\s-]/g, "_");
2243
+ const spanName = `think_${sanitizedName}`;
2076
2244
  this.log("Think step", { iteration: context.iteration });
2077
2245
  await this.triggerHook(HookEvents.LlmCall, { context, callType: "think" });
2246
+ const decisionSchema = createAgentDecisionWithOutputSchema(
2247
+ this.outputSchema
2248
+ );
2078
2249
  if (this.enableStreaming) {
2079
- return this.thinkStreaming(input, context);
2250
+ return this.thinkStreaming(input, context, decisionSchema, spanName);
2080
2251
  }
2081
2252
  try {
2082
2253
  const instructions = this.buildThinkInstructions();
@@ -2085,7 +2256,7 @@ var Agent = class extends BaseAgent {
2085
2256
  name: spanName,
2086
2257
  instructions,
2087
2258
  input: thinkContext,
2088
- outputSchema: AgentDecisionSchema,
2259
+ outputSchema: decisionSchema,
2089
2260
  model: this.model,
2090
2261
  ...context.parentSpanId && { parentSpanId: context.parentSpanId }
2091
2262
  });
@@ -2096,15 +2267,25 @@ var Agent = class extends BaseAgent {
2096
2267
  totalTokens: response.usage.totalTokens,
2097
2268
  cost: response.usage.cost
2098
2269
  });
2099
- const decision = AgentDecisionSchema.parse(response.jsonPayload);
2270
+ const decision = decisionSchema.parse(
2271
+ response.jsonPayload
2272
+ );
2100
2273
  await this.triggerHook(HookEvents.LlmResponse, {
2101
2274
  context,
2102
2275
  callType: "think",
2103
2276
  response
2104
2277
  });
2278
+ if (response.spanId) {
2279
+ await this.opperClient.updateSpan(response.spanId, void 0, {
2280
+ name: "think"
2281
+ });
2282
+ }
2105
2283
  await this.triggerHook(HookEvents.ThinkEnd, {
2106
2284
  context,
2107
- thought: { reasoning: decision.reasoning }
2285
+ thought: {
2286
+ reasoning: decision.reasoning,
2287
+ userMessage: decision.userMessage
2288
+ }
2108
2289
  });
2109
2290
  this.log("Think result", {
2110
2291
  reasoning: decision.reasoning,
@@ -2120,12 +2301,11 @@ var Agent = class extends BaseAgent {
2120
2301
  );
2121
2302
  }
2122
2303
  }
2123
- async thinkStreaming(input, context) {
2124
- const spanName = "think";
2304
+ async thinkStreaming(input, context, decisionSchema, spanName) {
2125
2305
  const instructions = this.buildThinkInstructions();
2126
2306
  const thinkContext = await this.buildThinkContext(input, context);
2127
2307
  const assembler = createStreamAssembler({
2128
- schema: AgentDecisionSchema
2308
+ schema: decisionSchema
2129
2309
  });
2130
2310
  let streamSpanId;
2131
2311
  await this.triggerHook(HookEvents.StreamStart, {
@@ -2141,7 +2321,7 @@ var Agent = class extends BaseAgent {
2141
2321
  name: spanName,
2142
2322
  instructions,
2143
2323
  input: thinkContext,
2144
- outputSchema: AgentDecisionSchema,
2324
+ outputSchema: decisionSchema,
2145
2325
  model: this.model,
2146
2326
  ...context.parentSpanId && { parentSpanId: context.parentSpanId }
2147
2327
  });
@@ -2185,11 +2365,11 @@ var Agent = class extends BaseAgent {
2185
2365
  const finalize = assembler.finalize();
2186
2366
  let decision;
2187
2367
  if (finalize.type === "structured" && finalize.structured) {
2188
- decision = AgentDecisionSchema.parse(
2368
+ decision = decisionSchema.parse(
2189
2369
  finalize.structured
2190
2370
  );
2191
2371
  } else {
2192
- decision = AgentDecisionSchema.parse({
2372
+ decision = decisionSchema.parse({
2193
2373
  reasoning: finalize.type === "root" ? finalize.rootText ?? "" : ""
2194
2374
  });
2195
2375
  }
@@ -2212,9 +2392,17 @@ var Agent = class extends BaseAgent {
2212
2392
  response: streamResponse,
2213
2393
  parsed: decision
2214
2394
  });
2395
+ if (streamSpanId) {
2396
+ await this.opperClient.updateSpan(streamSpanId, void 0, {
2397
+ name: "think"
2398
+ });
2399
+ }
2215
2400
  await this.triggerHook(HookEvents.ThinkEnd, {
2216
2401
  context,
2217
- thought: { reasoning: decision.reasoning }
2402
+ thought: {
2403
+ reasoning: decision.reasoning,
2404
+ userMessage: decision.userMessage
2405
+ }
2218
2406
  });
2219
2407
  this.log("Think result", {
2220
2408
  reasoning: decision.reasoning,
@@ -2256,12 +2444,22 @@ YOUR TASK:
2256
2444
  1. Analyze the current situation
2257
2445
  2. Decide if the goal is complete or more actions are needed
2258
2446
  3. If more actions needed: specify tools to call
2259
- 4. If goal complete: return empty tool_calls list
2447
+ 4. If goal complete:
2448
+ - Set isComplete=true
2449
+ - Provide the complete answer/output in finalResult
2450
+ - Leave toolCalls empty
2260
2451
 
2261
2452
  IMPORTANT:
2262
- - Return empty toolCalls array when task is COMPLETE
2453
+ - When task is COMPLETE, you MUST set isComplete=true AND provide finalResult
2454
+ - The finalResult should be a complete, well-structured answer based on all work done
2263
2455
  - Only use available tools
2264
- - Provide clear reasoning for each decision`;
2456
+ - Provide clear reasoning for each decision
2457
+ - If an outputSchema was specified, ensure finalResult matches that schema
2458
+
2459
+ USER MESSAGE:
2460
+ - Always provide a brief, user-friendly status in userMessage
2461
+ - This message is shown to users to indicate progress (e.g., "Searching for weather data...", "Calculating results...", "Done!")
2462
+ - Keep it concise and informative`;
2265
2463
  if (this.enableMemory) {
2266
2464
  instructions += `
2267
2465
 
@@ -2345,9 +2543,14 @@ The memory you write persists across all process() calls on this agent.`;
2345
2543
  this.log(`Action: ${toolCall.toolName}`, {
2346
2544
  parameters: toolCall.arguments
2347
2545
  });
2546
+ const startTime = /* @__PURE__ */ new Date();
2547
+ const tool2 = this.tools.get(toolCall.toolName);
2548
+ const isAgentTool = tool2?.metadata?.["isAgent"] === true;
2549
+ const spanType = isAgentTool ? "\u{1F916} agent" : "\u{1F527} tool";
2348
2550
  const toolSpan = await this.opperClient.createSpan({
2349
2551
  name: `tool_${toolCall.toolName}`,
2350
2552
  input: toolCall.arguments,
2553
+ type: spanType,
2351
2554
  ...parentSpanId ? { parentSpanId } : context.parentSpanId ? { parentSpanId: context.parentSpanId } : {}
2352
2555
  });
2353
2556
  try {
@@ -2357,11 +2560,20 @@ The memory you write persists across all process() calls on this agent.`;
2357
2560
  context,
2358
2561
  { spanId: toolSpan.id }
2359
2562
  );
2563
+ const endTime = /* @__PURE__ */ new Date();
2564
+ const durationMs = endTime.getTime() - startTime.getTime();
2360
2565
  if (result.success) {
2361
- await this.opperClient.updateSpan(toolSpan.id, result.output);
2566
+ await this.opperClient.updateSpan(toolSpan.id, result.output, {
2567
+ startTime,
2568
+ endTime,
2569
+ meta: { durationMs }
2570
+ });
2362
2571
  } else {
2363
2572
  await this.opperClient.updateSpan(toolSpan.id, void 0, {
2364
- error: result.error instanceof Error ? result.error.message : String(result.error)
2573
+ error: result.error instanceof Error ? result.error.message : String(result.error),
2574
+ startTime,
2575
+ endTime,
2576
+ meta: { durationMs }
2365
2577
  });
2366
2578
  }
2367
2579
  const summary = {
@@ -2376,12 +2588,18 @@ The memory you write persists across all process() calls on this agent.`;
2376
2588
  this.log(
2377
2589
  `Tool ${toolCall.toolName} ${result.success ? "succeeded" : "failed"}`,
2378
2590
  {
2379
- success: result.success
2591
+ success: result.success,
2592
+ durationMs
2380
2593
  }
2381
2594
  );
2382
2595
  } catch (error) {
2596
+ const endTime = /* @__PURE__ */ new Date();
2597
+ const durationMs = endTime.getTime() - startTime.getTime();
2383
2598
  await this.opperClient.updateSpan(toolSpan.id, void 0, {
2384
- error: error instanceof Error ? error.message : String(error)
2599
+ error: error instanceof Error ? error.message : String(error),
2600
+ startTime,
2601
+ endTime,
2602
+ meta: { durationMs }
2385
2603
  });
2386
2604
  const summary = {
2387
2605
  toolName: toolCall.toolName,
@@ -2390,7 +2608,8 @@ The memory you write persists across all process() calls on this agent.`;
2390
2608
  };
2391
2609
  results.push(ToolExecutionSummarySchema.parse(summary));
2392
2610
  this.logger.warn(`Tool ${toolCall.toolName} threw error`, {
2393
- error: error instanceof Error ? error.message : String(error)
2611
+ error: error instanceof Error ? error.message : String(error),
2612
+ durationMs
2394
2613
  });
2395
2614
  }
2396
2615
  }
@@ -2419,6 +2638,7 @@ The memory you write persists across all process() calls on this agent.`;
2419
2638
  const spanParentId = parentSpanId ?? context.parentSpanId ?? void 0;
2420
2639
  const summaries = [];
2421
2640
  if (hasReads) {
2641
+ const startTime = /* @__PURE__ */ new Date();
2422
2642
  try {
2423
2643
  const keySet = new Set(
2424
2644
  decision.memoryReads.filter(
@@ -2430,10 +2650,17 @@ The memory you write persists across all process() calls on this agent.`;
2430
2650
  const memoryReadSpan = await this.opperClient.createSpan({
2431
2651
  name: "memory_read",
2432
2652
  input: keys,
2653
+ type: "\u{1F9E0} memory",
2433
2654
  ...spanParentId && { parentSpanId: spanParentId }
2434
2655
  });
2435
2656
  const memoryData = await this.memory.read(keys);
2436
- await this.opperClient.updateSpan(memoryReadSpan.id, memoryData);
2657
+ const endTime = /* @__PURE__ */ new Date();
2658
+ const durationMs = endTime.getTime() - startTime.getTime();
2659
+ await this.opperClient.updateSpan(memoryReadSpan.id, memoryData, {
2660
+ startTime,
2661
+ endTime,
2662
+ meta: { durationMs }
2663
+ });
2437
2664
  context.setMetadata("current_memory", memoryData);
2438
2665
  this.log(`Loaded ${Object.keys(memoryData).length} memory entries`, {
2439
2666
  keys
@@ -2472,10 +2699,12 @@ The memory you write persists across all process() calls on this agent.`;
2472
2699
  }
2473
2700
  }
2474
2701
  if (hasWrites) {
2702
+ const startTime = /* @__PURE__ */ new Date();
2475
2703
  try {
2476
2704
  const memoryWriteSpan = await this.opperClient.createSpan({
2477
2705
  name: "memory_write",
2478
2706
  input: updateEntries.map(([key]) => key),
2707
+ type: "\u{1F9E0} memory",
2479
2708
  ...spanParentId && { parentSpanId: spanParentId }
2480
2709
  });
2481
2710
  for (const [key, update] of updateEntries) {
@@ -2492,9 +2721,16 @@ The memory you write persists across all process() calls on this agent.`;
2492
2721
  value: castUpdate.value
2493
2722
  });
2494
2723
  }
2724
+ const endTime = /* @__PURE__ */ new Date();
2725
+ const durationMs = endTime.getTime() - startTime.getTime();
2495
2726
  await this.opperClient.updateSpan(
2496
2727
  memoryWriteSpan.id,
2497
- `Successfully wrote ${updateEntries.length} keys`
2728
+ `Successfully wrote ${updateEntries.length} keys`,
2729
+ {
2730
+ startTime,
2731
+ endTime,
2732
+ meta: { durationMs }
2733
+ }
2498
2734
  );
2499
2735
  this.log(`Wrote ${updateEntries.length} memory entries`);
2500
2736
  summaries.push(
@@ -2567,8 +2803,10 @@ Follow any instructions provided for formatting and style.`;
2567
2803
  );
2568
2804
  }
2569
2805
  try {
2806
+ const sanitizedName = this.name.toLowerCase().replace(/[\s-]/g, "_");
2807
+ const functionName = `generate_final_result_${sanitizedName}`;
2570
2808
  const callOptions = {
2571
- name: "generate_final_result",
2809
+ name: functionName,
2572
2810
  instructions,
2573
2811
  input: finalContext,
2574
2812
  model: this.model
@@ -2615,8 +2853,10 @@ Follow any instructions provided for formatting and style.`;
2615
2853
  callType: "final_result"
2616
2854
  });
2617
2855
  try {
2856
+ const sanitizedName = this.name.toLowerCase().replace(/[\s-]/g, "_");
2857
+ const functionName = `generate_final_result_${sanitizedName}`;
2618
2858
  const streamResponse = await this.opperClient.stream({
2619
- name: "generate_final_result",
2859
+ name: functionName,
2620
2860
  instructions,
2621
2861
  input: finalContext,
2622
2862
  model: this.model,
@@ -3530,6 +3770,6 @@ var ToolRunner = class {
3530
3770
  }
3531
3771
  };
3532
3772
 
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 };
3773
+ 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, createAgentDecisionWithOutputSchema, createFunctionTool, createHookManager, createInMemoryStore, createMCPServerConfig, createOpperClient, createStreamAssembler, createToolCallRecord, err, extractTools, generateAgentFlowDiagram, getDefaultLogger, getSchemaDefault, isSchemaValid, isToolProvider, mcp, mergeSchemaDefaults, normalizeToolEntries, ok, schemaToJson, setDefaultLogger, tool, validateSchema, validateToolInput, zodSchemaToJsonSchema };
3534
3774
  //# sourceMappingURL=index.js.map
3535
3775
  //# sourceMappingURL=index.js.map