Skip to content

Commit 51bb3ee

Browse files
authored
v4 ai improvements (#1863)
* AI SDK sql generator and approval example WIP * Create some nice spans and extract the tools out so we can get the type of the streams * Enable AI SDK telemetry * Adding ai.tool and removing toolTask, 3rd party telemetry spans now wil create partials, better ai SDK telemetry icons * Created a separate d3-chat example, split out from the openai-agents example * Fixed the tool options being passed to metadata in `ai.tool` * Add a link to the run * Slightly improved design * Add a crawler task using crawl4ai * Use a tool to get the userId * Couple of tweaks * Adding markdown rendering to assistant messages and added an e2b based chart rendering task * Backup to anthropic * Add changeset
1 parent e539c7c commit 51bb3ee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

84 files changed

+3865
-515
lines changed

.changeset/honest-files-decide.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@trigger.dev/sdk": patch
3+
---
4+
5+
Deprecate toolTask and replace with `ai.tool(mySchemaTask)`

.vscode/launch.json

+8
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,14 @@
149149
"command": "pnpm run test ./src/run-queue/index.test.ts",
150150
"cwd": "${workspaceFolder}/internal-packages/run-engine",
151151
"sourceMaps": true
152+
},
153+
{
154+
"type": "node-terminal",
155+
"request": "launch",
156+
"name": "Debug d3-demo",
157+
"command": "pnpm exec trigger dev",
158+
"cwd": "${workspaceFolder}/references/d3-demo",
159+
"sourceMaps": true
152160
}
153161
]
154162
}

apps/webapp/app/components/runs/v3/RunIcon.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ export function RunIcon({ name, className, spanName }: TaskIconProps) {
7373
case "trigger":
7474
return <TriggerIcon className={cn(className, "text-orange-500")} />;
7575
case "python":
76-
return <PythonLogoIcon />;
76+
return <PythonLogoIcon className={className} />;
7777
//log levels
7878
case "debug":
7979
case "log":

apps/webapp/app/v3/otlpExporter.server.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class OTLPExporter {
5757

5858
const enrichedEvents = enrichCreatableEvents(events);
5959

60-
this.#logEventsVerbose(enrichedEvents);
60+
this.#logEventsVerbose(enrichedEvents, "exportTraces");
6161

6262
span.setAttribute("event_count", enrichedEvents.length);
6363

@@ -84,7 +84,7 @@ class OTLPExporter {
8484

8585
const enrichedEvents = enrichCreatableEvents(events);
8686

87-
this.#logEventsVerbose(enrichedEvents);
87+
this.#logEventsVerbose(enrichedEvents, "exportLogs");
8888

8989
span.setAttribute("event_count", enrichedEvents.length);
9090

@@ -98,11 +98,11 @@ class OTLPExporter {
9898
});
9999
}
100100

101-
#logEventsVerbose(events: CreatableEvent[]) {
101+
#logEventsVerbose(events: CreatableEvent[], prefix: string) {
102102
if (!this._verbose) return;
103103

104104
events.forEach((event) => {
105-
logger.debug("Exporting event", { event });
105+
logger.debug(`Exporting ${prefix} event`, { event });
106106
});
107107
}
108108

apps/webapp/app/v3/utils/enrichCreatableEvents.server.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function enrichStyle(event: CreatableEvent) {
2323
// GenAI System check
2424
const system = props["gen_ai.system"];
2525
if (typeof system === "string") {
26-
return { ...baseStyle, icon: `tabler-brand-${system}` };
26+
return { ...baseStyle, icon: `tabler-brand-${system.split(".")[0]}` };
2727
}
2828

2929
// Agent workflow check
@@ -32,6 +32,16 @@ function enrichStyle(event: CreatableEvent) {
3232
return { ...baseStyle, icon: "tabler-brain" };
3333
}
3434

35+
const message = event.message;
36+
37+
if (typeof message === "string" && message === "ai.toolCall") {
38+
return { ...baseStyle, icon: "tabler-tool" };
39+
}
40+
41+
if (typeof message === "string" && message.startsWith("ai.")) {
42+
return { ...baseStyle, icon: "tabler-sparkles" };
43+
}
44+
3545
return baseStyle;
3646
}
3747

apps/webapp/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -258,4 +258,4 @@
258258
"engines": {
259259
"node": ">=16.0.0"
260260
}
261-
}
261+
}

packages/cli-v3/src/entryPoints/dev-run-worker.ts

+2
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,8 @@ const zodIpc = new ZodIpcConnection({
433433
error: {
434434
type: "INTERNAL_ERROR",
435435
code: TaskRunErrorCodes.CONFIGURED_INCORRECTLY,
436+
message: err instanceof Error ? err.message : String(err),
437+
stackTrace: err instanceof Error ? err.stack : undefined,
436438
},
437439
usage: {
438440
durationMs: 0,

packages/core/src/v3/index.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,14 @@ export * from "./utils/imageRef.js";
7070
export * from "./utils/heartbeat.js";
7171

7272
export * from "./config.js";
73-
export { getSchemaParseFn, type AnySchemaParseFn, type SchemaParseFn } from "./types/schemas.js";
73+
export {
74+
getSchemaParseFn,
75+
type AnySchemaParseFn,
76+
type SchemaParseFn,
77+
isSchemaZodEsque,
78+
isSchemaValibotEsque,
79+
isSchemaArkTypeEsque,
80+
} from "./types/schemas.js";
7481

7582
import { VERSION } from "../version.js";
7683

packages/core/src/v3/otel/tracingSDK.ts

+1
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ export class TracingSDK {
142142

143143
traceProvider.addSpanProcessor(
144144
new TaskContextSpanProcessor(
145+
traceProvider.getTracer("trigger-dev-worker", VERSION),
145146
getEnvVar("OTEL_BATCH_PROCESSING_ENABLED") === "1"
146147
? new BatchSpanProcessor(spanExporter, {
147148
maxExportBatchSize: parseInt(getEnvVar("OTEL_SPAN_MAX_EXPORT_BATCH_SIZE") ?? "64"),

packages/core/src/v3/taskContext/otelProcessors.ts

+51-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,14 @@ import { SemanticInternalAttributes } from "../semanticInternalAttributes.js";
44
import { Context } from "@opentelemetry/api";
55
import { flattenAttributes } from "../utils/flattenAttributes.js";
66
import { taskContext } from "../task-context-api.js";
7+
import { Tracer } from "@opentelemetry/api";
78

89
export class TaskContextSpanProcessor implements SpanProcessor {
910
private _innerProcessor: SpanProcessor;
11+
private _tracer: Tracer;
1012

11-
constructor(innerProcessor: SpanProcessor) {
13+
constructor(tracer: Tracer, innerProcessor: SpanProcessor) {
14+
this._tracer = tracer;
1215
this._innerProcessor = innerProcessor;
1316
}
1417

@@ -26,7 +29,15 @@ export class TaskContextSpanProcessor implements SpanProcessor {
2629
);
2730
}
2831

29-
this._innerProcessor.onStart(span, parentContext);
32+
if (!isPartialSpan(span)) {
33+
const partialSpan = createPartialSpan(this._tracer, span, parentContext);
34+
35+
this._innerProcessor.onStart(span, parentContext);
36+
37+
partialSpan.end();
38+
} else {
39+
this._innerProcessor.onStart(span, parentContext);
40+
}
3041
}
3142

3243
// Delegate the rest of the methods to the wrapped processor
@@ -44,6 +55,44 @@ export class TaskContextSpanProcessor implements SpanProcessor {
4455
}
4556
}
4657

58+
function isPartialSpan(span: Span) {
59+
return span.attributes[SemanticInternalAttributes.SPAN_PARTIAL] === true;
60+
}
61+
62+
function createPartialSpan(tracer: Tracer, span: Span, parentContext: Context) {
63+
const partialSpan = tracer.startSpan(
64+
span.name,
65+
{
66+
attributes: {
67+
[SemanticInternalAttributes.SPAN_PARTIAL]: true,
68+
[SemanticInternalAttributes.SPAN_ID]: span.spanContext().spanId,
69+
...span.attributes,
70+
},
71+
},
72+
parentContext
73+
);
74+
75+
if (taskContext.ctx) {
76+
partialSpan.setAttributes(
77+
flattenAttributes(
78+
{
79+
[SemanticInternalAttributes.ATTEMPT_ID]: taskContext.ctx.attempt.id,
80+
[SemanticInternalAttributes.ATTEMPT_NUMBER]: taskContext.ctx.attempt.number,
81+
},
82+
SemanticInternalAttributes.METADATA
83+
)
84+
);
85+
}
86+
87+
if (span.events) {
88+
for (const event of span.events) {
89+
partialSpan.addEvent(event.name, event.attributes, event.time);
90+
}
91+
}
92+
93+
return partialSpan;
94+
}
95+
4796
export class TaskContextLogProcessor implements LogRecordProcessor {
4897
private _innerProcessor: LogRecordProcessor;
4998

packages/core/src/v3/tracer.ts

+4-43
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import {
22
Attributes,
33
Context,
4-
HrTime,
54
SpanOptions,
65
SpanStatusCode,
76
TimeInput,
@@ -12,12 +11,12 @@ import {
1211
type Tracer,
1312
} from "@opentelemetry/api";
1413
import { Logger, logs } from "@opentelemetry/api-logs";
15-
import { SemanticInternalAttributes } from "./semanticInternalAttributes.js";
1614
import { clock } from "./clock-api.js";
17-
import { usage } from "./usage-api.js";
18-
import { taskContext } from "./task-context-api.js";
19-
import { recordSpanException } from "./otel/utils.js";
2015
import { isCompleteTaskWithOutput } from "./errors.js";
16+
import { recordSpanException } from "./otel/utils.js";
17+
import { SemanticInternalAttributes } from "./semanticInternalAttributes.js";
18+
import { taskContext } from "./task-context-api.js";
19+
import { usage } from "./usage-api.js";
2120

2221
export type TriggerTracerConfig =
2322
| {
@@ -98,29 +97,6 @@ export class TriggerTracer {
9897
}
9998
});
10099

101-
if (taskContext.ctx) {
102-
const partialSpan = this.tracer.startSpan(
103-
name,
104-
{
105-
...options,
106-
attributes: {
107-
...attributes,
108-
[SemanticInternalAttributes.SPAN_PARTIAL]: true,
109-
[SemanticInternalAttributes.SPAN_ID]: span.spanContext().spanId,
110-
},
111-
},
112-
parentContext
113-
);
114-
115-
if (options?.events) {
116-
for (const event of options.events) {
117-
partialSpan.addEvent(event.name, event.attributes, event.startTime);
118-
}
119-
}
120-
121-
partialSpan.end();
122-
}
123-
124100
if (options?.events) {
125101
for (const event of options.events) {
126102
span.addEvent(event.name, event.attributes, event.startTime);
@@ -179,21 +155,6 @@ export class TriggerTracer {
179155

180156
const span = this.tracer.startSpan(name, options, parentContext);
181157

182-
this.tracer
183-
.startSpan(
184-
name,
185-
{
186-
...options,
187-
attributes: {
188-
...attributes,
189-
[SemanticInternalAttributes.SPAN_PARTIAL]: true,
190-
[SemanticInternalAttributes.SPAN_ID]: span.spanContext().spanId,
191-
},
192-
},
193-
parentContext
194-
)
195-
.end();
196-
197158
return span;
198159
}
199160
}

packages/core/src/v3/types/schemas.ts

+24
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,18 @@ export type SchemaZodEsque<TInput, TParsedInput> = {
33
_output: TParsedInput;
44
};
55

6+
export function isSchemaZodEsque<TInput, TParsedInput>(
7+
schema: Schema
8+
): schema is SchemaZodEsque<TInput, TParsedInput> {
9+
return (
10+
typeof schema === "object" &&
11+
"_def" in schema &&
12+
"parse" in schema &&
13+
"parseAsync" in schema &&
14+
"safeParse" in schema
15+
);
16+
}
17+
618
export type SchemaValibotEsque<TInput, TParsedInput> = {
719
schema: {
820
_types?: {
@@ -12,11 +24,23 @@ export type SchemaValibotEsque<TInput, TParsedInput> = {
1224
};
1325
};
1426

27+
export function isSchemaValibotEsque<TInput, TParsedInput>(
28+
schema: Schema
29+
): schema is SchemaValibotEsque<TInput, TParsedInput> {
30+
return typeof schema === "object" && "_types" in schema;
31+
}
32+
1533
export type SchemaArkTypeEsque<TInput, TParsedInput> = {
1634
inferIn: TInput;
1735
infer: TParsedInput;
1836
};
1937

38+
export function isSchemaArkTypeEsque<TInput, TParsedInput>(
39+
schema: Schema
40+
): schema is SchemaArkTypeEsque<TInput, TParsedInput> {
41+
return typeof schema === "object" && "_inferIn" in schema && "_infer" in schema;
42+
}
43+
2044
export type SchemaMyZodEsque<TInput> = {
2145
parse: (input: any) => TInput;
2246
};

packages/core/src/v3/workers/taskExecutor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,7 @@ export class TaskExecutor {
972972
},
973973
{
974974
attributes: {
975-
[SemanticInternalAttributes.STYLE_ICON]: "clock",
975+
[SemanticInternalAttributes.STYLE_ICON]: "tabler-clock",
976976
[SemanticInternalAttributes.COLLAPSED]: true,
977977
},
978978
}

packages/trigger-sdk/package.json

+24-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"exports": {
2424
"./package.json": "./package.json",
2525
".": "./src/v3/index.ts",
26-
"./v3": "./src/v3/index.ts"
26+
"./v3": "./src/v3/index.ts",
27+
"./ai": "./src/v3/ai.ts"
2728
},
2829
"sourceDialects": [
2930
"@triggerdotdev/source"
@@ -33,6 +34,9 @@
3334
"*": {
3435
"v3": [
3536
"dist/commonjs/v3/index.d.ts"
37+
],
38+
"ai": [
39+
"dist/commonjs/v3/ai.d.ts"
3640
]
3741
}
3842
},
@@ -66,7 +70,7 @@
6670
"@types/slug": "^5.0.3",
6771
"@types/uuid": "^9.0.0",
6872
"@types/ws": "^8.5.3",
69-
"ai": "^4.0.1",
73+
"ai": "^4.2.0",
7074
"encoding": "^0.1.13",
7175
"rimraf": "^3.0.2",
7276
"tshy": "^3.0.2",
@@ -75,7 +79,13 @@
7579
"zod": "3.23.8"
7680
},
7781
"peerDependencies": {
78-
"zod": "^3.0.0"
82+
"zod": "^3.0.0",
83+
"ai": "^4.2.0"
84+
},
85+
"peerDependenciesMeta": {
86+
"ai": {
87+
"optional": true
88+
}
7989
},
8090
"engines": {
8191
"node": ">=18.20.0"
@@ -103,6 +113,17 @@
103113
"types": "./dist/commonjs/v3/index.d.ts",
104114
"default": "./dist/commonjs/v3/index.js"
105115
}
116+
},
117+
"./ai": {
118+
"import": {
119+
"@triggerdotdev/source": "./src/v3/ai.ts",
120+
"types": "./dist/esm/v3/ai.d.ts",
121+
"default": "./dist/esm/v3/ai.js"
122+
},
123+
"require": {
124+
"types": "./dist/commonjs/v3/ai.d.ts",
125+
"default": "./dist/commonjs/v3/ai.js"
126+
}
106127
}
107128
},
108129
"main": "./dist/commonjs/v3/index.js",

0 commit comments

Comments
 (0)