@mastra/inngest 1.2.2 → 1.3.0-alpha.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/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { MessageList, Agent, TripWire } from '@mastra/core/agent';
2
2
  import { getErrorFromUnknown, MastraError, ErrorDomain, ErrorCategory } from '@mastra/core/error';
3
- import { EntityType, SpanType } from '@mastra/core/observability';
3
+ import { EntityType, SpanType, InternalSpans } from '@mastra/core/observability';
4
4
  import { ProcessorStepOutputSchema, ProcessorStepSchema, ProcessorRunner } from '@mastra/core/processors';
5
5
  import { toStandardSchema } from '@mastra/core/schema';
6
6
  import { createTool, Tool } from '@mastra/core/tools';
@@ -8,10 +8,11 @@ import { DefaultExecutionEngine, createTimeTravelExecutionParams, Run, hydrateSe
8
8
  import { PUBSUB_SYMBOL, STREAM_FORMAT_SYMBOL } from '@mastra/core/workflows/_constants';
9
9
  import { z } from 'zod';
10
10
  import { randomUUID } from 'crypto';
11
+ import { modelConfigSchema, baseIterationStateSchema, emitErrorEvent, createDurableLLMExecutionStep, createDurableToolCallStep, createDurableLLMMappingStep, createDurableBackgroundTaskCheckStep, DurableStepIds, createBaseIterationStateUpdate, durableAgenticOutputSchema, emitFinishEvent, createDurableAgentStream, prepareForDurableExecution, DurableAgentDefaults } from '@mastra/core/agent/durable';
11
12
  import { RequestContext } from '@mastra/core/di';
12
13
  import { NonRetriableError } from 'inngest';
13
14
  import { subscribe } from '@inngest/realtime';
14
- import { PubSub } from '@mastra/core/events';
15
+ import { PubSub, CachingPubSub } from '@mastra/core/events';
15
16
  import { ReadableStream } from 'stream/web';
16
17
  import { ChunkFrom, WorkflowRunOutput } from '@mastra/core/stream';
17
18
  import { context } from '@opentelemetry/api';
@@ -228,7 +229,8 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
228
229
  const span = observability.startSpan({
229
230
  ...options,
230
231
  traceId: executionContext.tracingIds?.traceId,
231
- parentSpanId
232
+ parentSpanId,
233
+ tracingPolicy: this.options?.tracingPolicy
232
234
  });
233
235
  return span?.exportSpan();
234
236
  });
@@ -516,6 +518,17 @@ var InngestExecutionEngine = class extends DefaultExecutionEngine {
516
518
  };
517
519
  }
518
520
  };
521
+ function parseTopic(topic) {
522
+ const workflowMatch = topic.match(/^workflow\.events\.v2\.(.+)$/);
523
+ if (workflowMatch && workflowMatch[1]) {
524
+ return { runId: workflowMatch[1], topicType: "workflow" };
525
+ }
526
+ const agentMatch = topic.match(/^agent\.stream\.(.+)$/);
527
+ if (agentMatch && agentMatch[1]) {
528
+ return { runId: agentMatch[1], topicType: "agent" };
529
+ }
530
+ return null;
531
+ }
519
532
  var InngestPubSub = class extends PubSub {
520
533
  inngest;
521
534
  workflowId;
@@ -530,60 +543,84 @@ var InngestPubSub = class extends PubSub {
530
543
  /**
531
544
  * Publish an event to Inngest's realtime system.
532
545
  *
533
- * Topic format: "workflow.events.v2.{runId}"
534
- * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
546
+ * Supported topic formats:
547
+ * - "workflow.events.v2.{runId}" - workflow events
548
+ * -> channel: "workflow:{workflowId}:{runId}", topic: "watch"
549
+ * - "agent.stream.{runId}" - agent stream events
550
+ * -> channel: "agent:{runId}", topic: "agent-stream"
551
+ * (Note: agent stream uses runId-only channel so nested workflows can publish to same channel)
535
552
  */
536
553
  async publish(topic, event) {
537
554
  if (!this.publishFn) {
538
555
  return;
539
556
  }
540
- const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
541
- if (!match) {
557
+ const parsed = parseTopic(topic);
558
+ if (!parsed) {
542
559
  return;
543
560
  }
544
- const runId = match[1];
561
+ const { runId, topicType } = parsed;
562
+ const inngestTopic = topicType === "agent" ? "agent-stream" : "watch";
563
+ const channel = topicType === "agent" ? `agent:${runId}` : `workflow:${this.workflowId}:${runId}`;
545
564
  try {
565
+ const dataToSend = topicType === "agent" ? event : event.data;
546
566
  await this.publishFn({
547
- channel: `workflow:${this.workflowId}:${runId}`,
548
- topic: "watch",
549
- data: event.data
567
+ channel,
568
+ topic: inngestTopic,
569
+ data: dataToSend
550
570
  });
551
571
  } catch (err) {
572
+ if (topicType === "agent" && (event.type === "finish" || event.type === "error")) {
573
+ throw err;
574
+ }
552
575
  console.error("InngestPubSub publish error:", err?.message ?? err);
553
576
  }
554
577
  }
555
578
  /**
556
579
  * Subscribe to events from Inngest's realtime system.
557
580
  *
558
- * Topic format: "workflow.events.v2.{runId}"
559
- * Maps to Inngest channel: "workflow:{workflowId}:{runId}"
581
+ * Supported topic formats:
582
+ * - "workflow.events.v2.{runId}" - workflow events
583
+ * -> channel: "workflow:{workflowId}:{runId}", topic: "watch"
584
+ * - "agent.stream.{runId}" - agent stream events
585
+ * -> channel: "agent:{runId}", topic: "agent-stream"
586
+ * (Note: agent stream uses runId-only channel so nested workflows can publish to same channel)
560
587
  */
561
588
  async subscribe(topic, cb) {
562
- const match = topic.match(/^workflow\.events\.v2\.(.+)$/);
563
- if (!match || !match[1]) {
589
+ const parsed = parseTopic(topic);
590
+ if (!parsed) {
564
591
  return;
565
592
  }
566
- const runId = match[1];
593
+ const { runId, topicType } = parsed;
567
594
  if (this.subscriptions.has(topic)) {
568
595
  this.subscriptions.get(topic).callbacks.add(cb);
569
596
  return;
570
597
  }
571
598
  const callbacks = /* @__PURE__ */ new Set([cb]);
572
- const channel = `workflow:${this.workflowId}:${runId}`;
573
- const streamPromise = subscribe(
599
+ const inngestTopic = topicType === "agent" ? "agent-stream" : "watch";
600
+ const channel = topicType === "agent" ? `agent:${runId}` : `workflow:${this.workflowId}:${runId}`;
601
+ const stream = await subscribe(
574
602
  {
575
603
  channel,
576
- topics: ["watch"],
604
+ topics: [inngestTopic],
577
605
  app: this.inngest
578
606
  },
579
607
  (message) => {
580
- const event = {
581
- id: crypto.randomUUID(),
582
- type: "watch",
583
- runId,
584
- data: message.data,
585
- createdAt: /* @__PURE__ */ new Date()
586
- };
608
+ let event;
609
+ if (topicType === "agent" && message.data?.type && message.data?.runId) {
610
+ event = {
611
+ id: crypto.randomUUID(),
612
+ createdAt: /* @__PURE__ */ new Date(),
613
+ ...message.data
614
+ };
615
+ } else {
616
+ event = {
617
+ id: crypto.randomUUID(),
618
+ type: inngestTopic,
619
+ runId,
620
+ data: message.data,
621
+ createdAt: /* @__PURE__ */ new Date()
622
+ };
623
+ }
587
624
  for (const callback of callbacks) {
588
625
  callback(event);
589
626
  }
@@ -591,9 +628,11 @@ var InngestPubSub = class extends PubSub {
591
628
  );
592
629
  this.subscriptions.set(topic, {
593
630
  unsubscribe: () => {
594
- streamPromise.then((stream) => stream.cancel()).catch((err) => {
631
+ try {
632
+ void stream.cancel();
633
+ } catch (err) {
595
634
  console.error("InngestPubSub unsubscribe error:", err);
596
- });
635
+ }
597
636
  },
598
637
  callbacks
599
638
  });
@@ -1575,13 +1614,26 @@ var InngestWorkflow = class _InngestWorkflow extends Workflow {
1575
1614
  }
1576
1615
  }
1577
1616
  });
1578
- } catch (error) {
1579
- throw error;
1617
+ } catch (executionError) {
1618
+ result = {
1619
+ status: "failed",
1620
+ steps: {},
1621
+ state: initialState ?? {},
1622
+ error: executionError instanceof Error ? executionError : new Error(String(executionError))
1623
+ };
1580
1624
  }
1581
1625
  let finalizeError;
1582
1626
  let finalizeErrored = false;
1583
1627
  try {
1584
1628
  await step.run(`workflow.${this.id}.finalize`, async () => {
1629
+ if (result.status === "failed" && inputData?.__workflowKind === "durable-agent" && inputData?.runId) {
1630
+ const error = result.error instanceof Error ? result.error : new Error(String(result.error));
1631
+ try {
1632
+ await emitErrorEvent(pubsub, inputData.runId, error);
1633
+ } catch (e) {
1634
+ this.logger.debug?.("Failed to emit error event:", e);
1635
+ }
1636
+ }
1585
1637
  if (result.status !== "paused") {
1586
1638
  await engine.invokeLifecycleCallbacksInternal({
1587
1639
  status: result.status,
@@ -1750,6 +1802,560 @@ var serve = createServe(serve$1);
1750
1802
 
1751
1803
  // src/types.ts
1752
1804
  var _compatibilityCheck = true;
1805
+ var durableAgenticInputSchema = z.object({
1806
+ runId: z.string(),
1807
+ agentId: z.string(),
1808
+ agentName: z.string().optional(),
1809
+ messageListState: z.any(),
1810
+ toolsMetadata: z.array(z.any()),
1811
+ modelConfig: modelConfigSchema,
1812
+ options: z.any(),
1813
+ state: z.any(),
1814
+ messageId: z.string(),
1815
+ // Observability fields (Inngest-specific)
1816
+ agentSpanData: z.any().optional(),
1817
+ modelSpanData: z.any().optional(),
1818
+ stepIndex: z.number().optional()
1819
+ });
1820
+ var iterationStateSchema = baseIterationStateSchema.extend({
1821
+ // Observability - exported span data for agent run
1822
+ agentSpanData: z.any().optional(),
1823
+ // Observability - exported span data for model generation (ONE span for entire run)
1824
+ modelSpanData: z.any().optional(),
1825
+ // Step index for continuation across iterations (maintains step: 0, 1, 2, ...)
1826
+ stepIndex: z.number()
1827
+ });
1828
+ var INNGEST_ENGINE_PREFIX = "inngest";
1829
+ var InngestDurableStepIds = {
1830
+ AGENTIC_EXECUTION: `${INNGEST_ENGINE_PREFIX}:${DurableStepIds.AGENTIC_EXECUTION}`,
1831
+ AGENTIC_LOOP: `${INNGEST_ENGINE_PREFIX}:${DurableStepIds.AGENTIC_LOOP}`
1832
+ };
1833
+ function createInngestDurableAgenticWorkflow(options) {
1834
+ const { inngest, maxSteps = DurableAgentDefaults.MAX_STEPS } = options;
1835
+ const { createWorkflow } = init(inngest);
1836
+ const llmExecutionStep = createDurableLLMExecutionStep();
1837
+ const toolCallStep = createDurableToolCallStep();
1838
+ const llmMappingStep = createDurableLLMMappingStep();
1839
+ const backgroundTaskCheckStep = createDurableBackgroundTaskCheckStep();
1840
+ const singleIterationWorkflow = createWorkflow({
1841
+ id: InngestDurableStepIds.AGENTIC_EXECUTION,
1842
+ inputSchema: iterationStateSchema,
1843
+ outputSchema: iterationStateSchema,
1844
+ options: {
1845
+ tracingPolicy: {
1846
+ // Mark all workflow spans as internal so they're hidden in traces
1847
+ // This makes the trace structure match regular agents (agent_run -> model_generation -> tool_call)
1848
+ internal: InternalSpans.WORKFLOW
1849
+ },
1850
+ shouldPersistSnapshot: ({ workflowStatus }) => workflowStatus === "suspended",
1851
+ validateInputs: false
1852
+ },
1853
+ steps: []
1854
+ }).map(
1855
+ async ({ inputData }) => {
1856
+ const state = inputData;
1857
+ return {
1858
+ runId: state.runId,
1859
+ agentId: state.agentId,
1860
+ agentName: state.agentName,
1861
+ messageListState: state.messageListState,
1862
+ toolsMetadata: state.toolsMetadata,
1863
+ modelConfig: state.modelConfig,
1864
+ options: state.options,
1865
+ state: state.state,
1866
+ messageId: state.messageId,
1867
+ // Pass agent span data so model spans can use it as parent
1868
+ agentSpanData: state.agentSpanData,
1869
+ // Pass model span data (ONE span for entire agent run)
1870
+ modelSpanData: state.modelSpanData,
1871
+ // Pass step index for continuation (step: 0, 1, 2, ...)
1872
+ stepIndex: state.stepIndex
1873
+ };
1874
+ },
1875
+ { id: "map-to-llm-input" }
1876
+ ).then(llmExecutionStep).map(
1877
+ async ({ inputData }) => {
1878
+ const llmOutput = inputData;
1879
+ return llmOutput.toolCalls ?? [];
1880
+ },
1881
+ { id: "extract-tool-calls" }
1882
+ ).foreach(toolCallStep).map(
1883
+ async ({ inputData, getStepResult, getInitData, mastra }) => {
1884
+ const toolResults = inputData;
1885
+ const llmOutput = getStepResult(llmExecutionStep.id);
1886
+ const initData = getInitData();
1887
+ const observability = mastra?.observability?.getSelectedInstance({});
1888
+ const modelSpanData = llmOutput?.modelSpanData;
1889
+ const stepSpanData = llmOutput?.stepSpanData;
1890
+ const modelSpan = modelSpanData ? observability?.rebuildSpan(modelSpanData) : void 0;
1891
+ const stepSpan = stepSpanData ? observability?.rebuildSpan(stepSpanData) : void 0;
1892
+ const agentSpan = initData.agentSpanData ? observability?.rebuildSpan(initData.agentSpanData) : void 0;
1893
+ const toolParentSpan = stepSpan ?? modelSpan ?? agentSpan;
1894
+ for (const tr of toolResults) {
1895
+ const toolSpan = toolParentSpan?.createChildSpan({
1896
+ type: SpanType.TOOL_CALL,
1897
+ name: `tool: '${tr.toolName}'`,
1898
+ entityType: EntityType.TOOL,
1899
+ entityId: tr.toolName,
1900
+ entityName: tr.toolName,
1901
+ input: tr.args
1902
+ });
1903
+ if (tr.error) {
1904
+ toolSpan?.error({ error: new Error(tr.error.message) });
1905
+ } else {
1906
+ toolSpan?.end({ output: tr.result });
1907
+ }
1908
+ if (!tr.error) {
1909
+ stepSpan?.createEventSpan({
1910
+ type: SpanType.MODEL_CHUNK,
1911
+ name: `chunk: 'tool-result'`,
1912
+ output: {
1913
+ toolCallId: tr.toolCallId,
1914
+ toolName: tr.toolName,
1915
+ result: tr.result
1916
+ }
1917
+ });
1918
+ }
1919
+ }
1920
+ const toolCalls = llmOutput?.toolCalls ?? [];
1921
+ if (stepSpan) {
1922
+ const stepFinishPayload = llmOutput.stepFinishPayload;
1923
+ stepSpan.end({
1924
+ output: {
1925
+ toolCalls: toolCalls.map((tc) => ({
1926
+ toolCallId: tc.toolCallId,
1927
+ toolName: tc.toolName,
1928
+ args: tc.args
1929
+ })),
1930
+ toolResults: toolResults.map((tr) => ({
1931
+ toolCallId: tr.toolCallId,
1932
+ toolName: tr.toolName,
1933
+ result: tr.result,
1934
+ error: tr.error
1935
+ }))
1936
+ },
1937
+ attributes: {
1938
+ usage: stepFinishPayload?.output?.usage,
1939
+ finishReason: stepFinishPayload?.stepResult?.reason,
1940
+ isContinued: stepFinishPayload?.stepResult?.isContinued
1941
+ }
1942
+ });
1943
+ }
1944
+ return {
1945
+ llmOutput,
1946
+ toolResults,
1947
+ runId: initData.runId,
1948
+ agentId: initData.agentId,
1949
+ messageId: initData.messageId,
1950
+ state: llmOutput?.state ?? initData.state
1951
+ };
1952
+ },
1953
+ { id: "collect-tool-results" }
1954
+ ).then(llmMappingStep).then(backgroundTaskCheckStep).map(
1955
+ async ({ inputData, getInitData }) => {
1956
+ const executionOutput = inputData;
1957
+ const initData = getInitData();
1958
+ const baseUpdate = createBaseIterationStateUpdate({
1959
+ currentState: initData,
1960
+ executionOutput
1961
+ });
1962
+ const newIterationState = {
1963
+ ...baseUpdate,
1964
+ // Preserve agent span data for observability
1965
+ agentSpanData: initData.agentSpanData,
1966
+ // Preserve model span data (ONE span for entire agent run)
1967
+ modelSpanData: initData.modelSpanData,
1968
+ // Increment step index for next iteration (step: 0 → 1 → 2 → ...)
1969
+ stepIndex: initData.stepIndex + 1
1970
+ };
1971
+ return newIterationState;
1972
+ },
1973
+ { id: "update-iteration-state" }
1974
+ ).commit();
1975
+ return createWorkflow({
1976
+ id: InngestDurableStepIds.AGENTIC_LOOP,
1977
+ inputSchema: durableAgenticInputSchema,
1978
+ outputSchema: durableAgenticOutputSchema,
1979
+ options: {
1980
+ tracingPolicy: {
1981
+ // Mark all workflow spans as internal so they're hidden in traces
1982
+ // This makes the trace structure match regular agents (agent_run -> model_generation -> tool_call)
1983
+ internal: InternalSpans.WORKFLOW
1984
+ },
1985
+ shouldPersistSnapshot: ({ workflowStatus }) => workflowStatus === "suspended",
1986
+ validateInputs: false
1987
+ },
1988
+ steps: []
1989
+ }).map(
1990
+ async ({ inputData }) => {
1991
+ const input = inputData;
1992
+ const agentSpanData = input.agentSpanData;
1993
+ const modelSpanData = input.modelSpanData;
1994
+ const iterationState = {
1995
+ ...input,
1996
+ iterationCount: 0,
1997
+ accumulatedSteps: [],
1998
+ accumulatedUsage: {
1999
+ inputTokens: 0,
2000
+ outputTokens: 0,
2001
+ totalTokens: 0
2002
+ },
2003
+ lastStepResult: void 0,
2004
+ agentSpanData,
2005
+ modelSpanData,
2006
+ stepIndex: input.stepIndex ?? 0
2007
+ };
2008
+ return iterationState;
2009
+ },
2010
+ { id: "init-iteration-state" }
2011
+ ).dowhile(singleIterationWorkflow, async ({ inputData }) => {
2012
+ const state = inputData;
2013
+ const shouldContinue = state.lastStepResult?.isContinued === true;
2014
+ const effectiveMaxSteps = state.options?.maxSteps ?? maxSteps;
2015
+ const underMaxSteps = state.iterationCount < effectiveMaxSteps;
2016
+ return shouldContinue && underMaxSteps;
2017
+ }).map(
2018
+ async (params) => {
2019
+ const { inputData, mastra } = params;
2020
+ const state = inputData;
2021
+ const pubsub = params[PUBSUB_SYMBOL];
2022
+ const lastStep = state.accumulatedSteps[state.accumulatedSteps.length - 1];
2023
+ const finalText = lastStep?.text;
2024
+ const finalOutput = {
2025
+ messageListState: state.messageListState,
2026
+ messageId: state.messageId,
2027
+ stepResult: state.lastStepResult || {
2028
+ reason: "stop",
2029
+ warnings: [],
2030
+ isContinued: false
2031
+ },
2032
+ output: {
2033
+ text: finalText,
2034
+ usage: state.accumulatedUsage,
2035
+ steps: state.accumulatedSteps
2036
+ },
2037
+ state: state.state
2038
+ };
2039
+ const observability = mastra?.observability?.getSelectedInstance({});
2040
+ if (state.modelSpanData) {
2041
+ const modelSpan = observability?.rebuildSpan(state.modelSpanData);
2042
+ modelSpan?.end({
2043
+ output: {
2044
+ text: finalText,
2045
+ usage: state.accumulatedUsage
2046
+ },
2047
+ attributes: {
2048
+ finishReason: state.lastStepResult?.reason || "stop"
2049
+ }
2050
+ });
2051
+ }
2052
+ if (state.agentSpanData) {
2053
+ const agentSpan = observability?.rebuildSpan(state.agentSpanData);
2054
+ agentSpan?.end({
2055
+ output: finalOutput.output
2056
+ });
2057
+ }
2058
+ if (pubsub) {
2059
+ await emitFinishEvent(pubsub, state.runId, {
2060
+ output: finalOutput.output,
2061
+ stepResult: finalOutput.stepResult
2062
+ });
2063
+ }
2064
+ return finalOutput;
2065
+ },
2066
+ { id: "map-final-output" }
2067
+ ).commit();
2068
+ }
2069
+
2070
+ // src/durable-agent/create-inngest-agent.ts
2071
+ function createInngestAgent(options) {
2072
+ const {
2073
+ agent,
2074
+ inngest,
2075
+ id: idOverride,
2076
+ name: nameOverride,
2077
+ pubsub: customPubsub,
2078
+ cache,
2079
+ mastra: mastraOption
2080
+ } = options;
2081
+ const agentId = idOverride ?? agent.id;
2082
+ const agentName = nameOverride ?? agent.name;
2083
+ let mastra = mastraOption;
2084
+ const workflow = createInngestDurableAgenticWorkflow({ inngest });
2085
+ let _customCache = cache;
2086
+ let innerPubsub = customPubsub ?? new InngestPubSub(inngest, InngestDurableStepIds.AGENTIC_LOOP);
2087
+ let _cachingPubsub = null;
2088
+ function getPubsub() {
2089
+ if (!_cachingPubsub) {
2090
+ const resolvedCache = _customCache ?? mastra?.serverCache;
2091
+ if (resolvedCache) {
2092
+ _customCache = resolvedCache;
2093
+ _cachingPubsub = new CachingPubSub(innerPubsub, resolvedCache);
2094
+ } else {
2095
+ _cachingPubsub = innerPubsub;
2096
+ }
2097
+ }
2098
+ return _cachingPubsub;
2099
+ }
2100
+ function getCache() {
2101
+ getPubsub();
2102
+ return _customCache;
2103
+ }
2104
+ async function triggerWorkflow(runId, workflowInput, tracingOptions) {
2105
+ const eventName = `workflow.${InngestDurableStepIds.AGENTIC_LOOP}`;
2106
+ await inngest.send({
2107
+ name: eventName,
2108
+ data: {
2109
+ inputData: workflowInput,
2110
+ runId,
2111
+ resourceId: workflowInput.state?.resourceId,
2112
+ requestContext: {},
2113
+ tracingOptions
2114
+ }
2115
+ });
2116
+ }
2117
+ async function emitError(runId, error) {
2118
+ await emitErrorEvent(getPubsub(), runId, error);
2119
+ }
2120
+ const inngestAgent = {
2121
+ get id() {
2122
+ return agentId;
2123
+ },
2124
+ get name() {
2125
+ return agentName;
2126
+ },
2127
+ get agent() {
2128
+ return agent;
2129
+ },
2130
+ get inngest() {
2131
+ return inngest;
2132
+ },
2133
+ get cache() {
2134
+ return getCache();
2135
+ },
2136
+ get pubsub() {
2137
+ return getPubsub();
2138
+ },
2139
+ async stream(messages, streamOptions) {
2140
+ const preparation = await prepareForDurableExecution({
2141
+ agent,
2142
+ messages,
2143
+ options: streamOptions,
2144
+ runId: streamOptions?.runId,
2145
+ requestContext: streamOptions?.requestContext
2146
+ });
2147
+ const { runId, messageId, workflowInput, threadId, resourceId } = preparation;
2148
+ workflowInput.agentId = agentId;
2149
+ workflowInput.agentName = agentName;
2150
+ const observability = mastra?.observability?.getSelectedInstance({
2151
+ requestContext: streamOptions?.requestContext
2152
+ });
2153
+ const agentSpan = observability?.startSpan({
2154
+ type: SpanType.AGENT_RUN,
2155
+ name: `agent run: '${agentId}'`,
2156
+ entityType: EntityType.AGENT,
2157
+ entityId: agentId,
2158
+ entityName: agentName,
2159
+ input: workflowInput.messageListState,
2160
+ metadata: {
2161
+ runId,
2162
+ threadId,
2163
+ resourceId
2164
+ }
2165
+ });
2166
+ const agentSpanData = agentSpan?.exportSpan();
2167
+ const modelSpan = agentSpan?.createChildSpan({
2168
+ type: SpanType.MODEL_GENERATION,
2169
+ name: `llm: '${workflowInput.modelConfig.modelId}'`,
2170
+ input: { messages: workflowInput.messageListState },
2171
+ attributes: {
2172
+ model: workflowInput.modelConfig.modelId,
2173
+ provider: workflowInput.modelConfig.provider,
2174
+ streaming: true,
2175
+ parameters: {
2176
+ temperature: workflowInput.options?.temperature
2177
+ }
2178
+ }
2179
+ });
2180
+ const modelSpanData = modelSpan?.exportSpan();
2181
+ workflowInput.agentSpanData = agentSpanData;
2182
+ workflowInput.modelSpanData = modelSpanData;
2183
+ workflowInput.stepIndex = 0;
2184
+ const {
2185
+ output,
2186
+ cleanup: streamCleanup,
2187
+ ready
2188
+ } = createDurableAgentStream({
2189
+ pubsub: getPubsub(),
2190
+ runId,
2191
+ messageId,
2192
+ model: {
2193
+ modelId: workflowInput.modelConfig.modelId,
2194
+ provider: workflowInput.modelConfig.provider,
2195
+ version: "v3"
2196
+ },
2197
+ threadId,
2198
+ resourceId,
2199
+ onChunk: streamOptions?.onChunk,
2200
+ onStepFinish: streamOptions?.onStepFinish,
2201
+ onFinish: streamOptions?.onFinish,
2202
+ onError: streamOptions?.onError,
2203
+ onSuspended: streamOptions?.onSuspended
2204
+ });
2205
+ const tracingOptions = agentSpanData ? { traceId: agentSpanData.traceId, parentSpanId: agentSpanData.id } : void 0;
2206
+ ready.then(() => triggerWorkflow(runId, workflowInput, tracingOptions)).catch((error) => {
2207
+ void emitError(runId, error);
2208
+ });
2209
+ const result = {
2210
+ output,
2211
+ runId,
2212
+ threadId,
2213
+ resourceId,
2214
+ cleanup: streamCleanup,
2215
+ // Also expose fullStream directly for server compatibility
2216
+ get fullStream() {
2217
+ return output.fullStream;
2218
+ }
2219
+ };
2220
+ return result;
2221
+ },
2222
+ async resume(runId, resumeData, resumeOptions) {
2223
+ const {
2224
+ output,
2225
+ cleanup: streamCleanup,
2226
+ ready
2227
+ } = createDurableAgentStream({
2228
+ pubsub: getPubsub(),
2229
+ runId,
2230
+ messageId: crypto.randomUUID(),
2231
+ model: {
2232
+ modelId: void 0,
2233
+ provider: void 0,
2234
+ version: "v3"
2235
+ },
2236
+ threadId: resumeOptions?.threadId,
2237
+ resourceId: resumeOptions?.resourceId,
2238
+ onChunk: resumeOptions?.onChunk,
2239
+ onStepFinish: resumeOptions?.onStepFinish,
2240
+ onFinish: resumeOptions?.onFinish,
2241
+ onError: resumeOptions?.onError,
2242
+ onSuspended: resumeOptions?.onSuspended
2243
+ });
2244
+ const eventName = `workflow.${InngestDurableStepIds.AGENTIC_LOOP}`;
2245
+ ready.then(async () => {
2246
+ const workflowsStore = await mastra?.getStorage()?.getStore("workflows");
2247
+ const snapshot = await workflowsStore?.loadWorkflowSnapshot({
2248
+ workflowName: InngestDurableStepIds.AGENTIC_LOOP,
2249
+ runId
2250
+ });
2251
+ const suspendedStepIds = snapshot?.suspendedPaths ? Object.keys(snapshot.suspendedPaths) : [];
2252
+ const steps = suspendedStepIds.length > 0 ? suspendedStepIds : [];
2253
+ await inngest.send({
2254
+ name: eventName,
2255
+ data: {
2256
+ inputData: resumeData,
2257
+ initialState: snapshot?.value ?? {},
2258
+ runId,
2259
+ resourceId: resumeOptions?.resourceId,
2260
+ requestContext: {},
2261
+ stepResults: snapshot?.context,
2262
+ resume: {
2263
+ steps,
2264
+ stepResults: snapshot?.context,
2265
+ resumePayload: resumeData,
2266
+ resumePath: steps[0] ? snapshot?.suspendedPaths?.[steps[0]] : void 0
2267
+ }
2268
+ }
2269
+ });
2270
+ }).catch((error) => {
2271
+ void emitError(runId, error);
2272
+ });
2273
+ return {
2274
+ output,
2275
+ get fullStream() {
2276
+ return output.fullStream;
2277
+ },
2278
+ runId,
2279
+ threadId: resumeOptions?.threadId,
2280
+ resourceId: resumeOptions?.resourceId,
2281
+ cleanup: streamCleanup
2282
+ };
2283
+ },
2284
+ async prepare(messages, prepareOptions) {
2285
+ const preparation = await prepareForDurableExecution({
2286
+ agent,
2287
+ messages,
2288
+ options: prepareOptions,
2289
+ requestContext: prepareOptions?.requestContext
2290
+ });
2291
+ preparation.workflowInput.agentId = agentId;
2292
+ preparation.workflowInput.agentName = agentName;
2293
+ return {
2294
+ runId: preparation.runId,
2295
+ messageId: preparation.messageId,
2296
+ workflowInput: preparation.workflowInput,
2297
+ threadId: preparation.threadId,
2298
+ resourceId: preparation.resourceId
2299
+ };
2300
+ },
2301
+ async observe(runId, observeOptions) {
2302
+ const {
2303
+ output,
2304
+ cleanup: streamCleanup,
2305
+ ready
2306
+ } = createDurableAgentStream({
2307
+ pubsub: getPubsub(),
2308
+ runId,
2309
+ messageId: crypto.randomUUID(),
2310
+ model: {
2311
+ modelId: void 0,
2312
+ provider: void 0,
2313
+ version: "v3"
2314
+ },
2315
+ offset: observeOptions?.offset,
2316
+ onChunk: observeOptions?.onChunk,
2317
+ onStepFinish: observeOptions?.onStepFinish,
2318
+ onFinish: observeOptions?.onFinish,
2319
+ onError: observeOptions?.onError,
2320
+ onSuspended: observeOptions?.onSuspended
2321
+ });
2322
+ await ready;
2323
+ return {
2324
+ output,
2325
+ get fullStream() {
2326
+ return output.fullStream;
2327
+ },
2328
+ runId,
2329
+ cleanup: streamCleanup
2330
+ };
2331
+ },
2332
+ getDurableWorkflows() {
2333
+ return [workflow];
2334
+ },
2335
+ __setMastra(mastraInstance) {
2336
+ mastra = mastraInstance;
2337
+ }
2338
+ };
2339
+ return new Proxy(inngestAgent, {
2340
+ get(target, prop, receiver) {
2341
+ if (prop in target) {
2342
+ return Reflect.get(target, prop, receiver);
2343
+ }
2344
+ const agentValue = agent[prop];
2345
+ if (typeof agentValue === "function") {
2346
+ return agentValue.bind(agent);
2347
+ }
2348
+ return agentValue;
2349
+ },
2350
+ has(target, prop) {
2351
+ return prop in target || prop in agent;
2352
+ }
2353
+ });
2354
+ }
2355
+ function isInngestAgent(obj) {
2356
+ if (!obj) return false;
2357
+ return typeof obj.id === "string" && typeof obj.name === "string" && "agent" in obj && "inngest" in obj && typeof obj.stream === "function" && typeof obj.getDurableWorkflows === "function";
2358
+ }
1753
2359
 
1754
2360
  // src/index.ts
1755
2361
  function isInngestWorkflow(input) {
@@ -2466,6 +3072,6 @@ function init(inngest) {
2466
3072
  };
2467
3073
  }
2468
3074
 
2469
- export { InngestExecutionEngine, InngestPubSub, InngestRun, InngestWorkflow, _compatibilityCheck, createServe, createStep, init, serve };
3075
+ export { InngestExecutionEngine, InngestPubSub, InngestRun, InngestWorkflow, _compatibilityCheck, createInngestAgent, createInngestDurableAgenticWorkflow, createServe, createStep, init, isInngestAgent, serve };
2470
3076
  //# sourceMappingURL=index.js.map
2471
3077
  //# sourceMappingURL=index.js.map