@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/CHANGELOG.md +112 -0
- package/dist/__tests__/adapters/_utils.d.ts +2 -2
- package/dist/__tests__/durable-agent.test.utils.d.ts +43 -0
- package/dist/__tests__/durable-agent.test.utils.d.ts.map +1 -0
- package/dist/durable-agent/create-inngest-agent.d.ts +300 -0
- package/dist/durable-agent/create-inngest-agent.d.ts.map +1 -0
- package/dist/durable-agent/create-inngest-agentic-workflow.d.ts +55 -0
- package/dist/durable-agent/create-inngest-agentic-workflow.d.ts.map +1 -0
- package/dist/durable-agent/index.d.ts +50 -0
- package/dist/durable-agent/index.d.ts.map +1 -0
- package/dist/execution-engine.d.ts.map +1 -1
- package/dist/index.cjs +637 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +637 -31
- package/dist/index.js.map +1 -1
- package/dist/pubsub.d.ts +17 -6
- package/dist/pubsub.d.ts.map +1 -1
- package/dist/serve.d.ts.map +1 -1
- package/dist/workflow.d.ts.map +1 -1
- package/package.json +14 -12
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
|
-
*
|
|
534
|
-
*
|
|
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
|
|
541
|
-
if (!
|
|
557
|
+
const parsed = parseTopic(topic);
|
|
558
|
+
if (!parsed) {
|
|
542
559
|
return;
|
|
543
560
|
}
|
|
544
|
-
const runId =
|
|
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
|
|
548
|
-
topic:
|
|
549
|
-
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
|
-
*
|
|
559
|
-
*
|
|
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
|
|
563
|
-
if (!
|
|
589
|
+
const parsed = parseTopic(topic);
|
|
590
|
+
if (!parsed) {
|
|
564
591
|
return;
|
|
565
592
|
}
|
|
566
|
-
const runId =
|
|
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
|
|
573
|
-
const
|
|
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: [
|
|
604
|
+
topics: [inngestTopic],
|
|
577
605
|
app: this.inngest
|
|
578
606
|
},
|
|
579
607
|
(message) => {
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
|
|
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 (
|
|
1579
|
-
|
|
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
|