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