Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 22 additions & 9 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,15 @@
- [Maintenance](#maintenance)
- [Getting started](#getting-started)
- [Contributor License Agreement (CLA)](#contributor-license-agreement-cla)
- [SDK Structure](#sdk-structure)
- [Environment setup](#environment-setup)
- [Development](#development)
- [Working with Individual Packages](#working-with-individual-packages)
- [Testing](#testing)
- [Testing local changes to core](#testing-local-changes-to-core)
- [Integration tests](#integration-tests)
- [Integration tests](#integration-tests)
- [test-npm-init](#test-npm-init)
- [Style Guide](#style-guide)
- [Publishing](#publishing)
- [Updating published packages](#updating-published-packages)
- [Updating and pruning dependencies](#updating-and-pruning-dependencies)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -69,9 +68,9 @@ a version manager, such as [fnm](https://github.com/Schniz/fnm) or [nvm](https:/
6. Install `pnpm`
TS SDK uses PNPM to manage dependencies. Corepack is the recommend way to install `pnpm` and is included in Node 14+

```sh
corepack enable
```
```sh
corepack enable
```

7. Install the dependencies:

Expand All @@ -90,7 +89,7 @@ pnpm run build
If building fails, resetting your environment may help:

```
pnpm run clean -y
pnpm run clean
pnpm install --frozen-lockfile
```

Expand All @@ -112,14 +111,28 @@ After your environment is set up, you can run these commands:
- `pnpm run lint` verifies code style with prettier and ES lint.
- `pnpm run commitlint` validates [commit messages](#style-guide).

### Working with Individual Packages

You can build or test a single package using pnpm's filter flag:

```sh
# Build a single package and all its dependencies explicitly
pnpm -F @temporalio/worker... run build

# Run tests for a single package
pnpm -F @temporalio/common run test
```

The `...` suffix includes all dependencies of the specified package.

### Testing

#### Testing local changes to core

Create a `.cargo/config.toml` file and override the path to sdk-core and/or sdk-core-protos as
described [here](https://doc.rust-lang.org/cargo/reference/overriding-dependencies.html#paths-overrides)

##### Integration tests
#### Integration tests

In order to run integration tests:

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"build": "pnpm --recursive --stream run build",
"build:watch": "pnpm run build:protos && tsc --build --watch packages/*/tsconfig.json",
"build:protos": "tsx ./packages/proto/scripts/compile-proto.ts",
"test": "pnpm --recursive --stream run test",
"test": "pnpm --recursive --parallel --stream run test",
"test:watch": "pnpm --recursive --stream run test:watch",
"ci-stress": "node ./packages/test/lib/load/run-all-stress-ci-scenarios.js",
"ci-nightly": "node ./packages/test/lib/load/run-all-nightly-scenarios.js",
Expand Down
3 changes: 3 additions & 0 deletions packages/activity/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
],
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
"license": "MIT",
"scripts": {
"build": "tsc --build"
},
"dependencies": {
"@temporalio/client": "workspace:*",
"@temporalio/common": "workspace:*",
Expand Down
33 changes: 32 additions & 1 deletion packages/ai-sdk/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@
],
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
"license": "MIT",
"scripts": {
"build": "tsc --build",
"test": "ava ./lib/__tests__/test-*.js"
},
"ava": {
"timeout": "120s",
"concurrency": 1,
"workerThreads": false
},
"dependencies": {
"@temporalio/common": "workspace:*",
"@temporalio/plugin": "workspace:*",
Expand All @@ -27,6 +36,26 @@
"@ai-sdk/provider": "^3.0.0",
"ai": "^6.0.0"
},
"devDependencies": {
"@ai-sdk/mcp": "^1.0.0",
"@ai-sdk/openai": "^3.0.0",
"@ai-sdk/provider": "^3.0.0",
"@modelcontextprotocol/sdk": "^1.25.2",
"@opentelemetry/api": "^1.9.0",
"@opentelemetry/core": "^1.25.1",
"@opentelemetry/sdk-node": "^0.52.1",
"@opentelemetry/semantic-conventions": "^1.25.1",
"@temporalio/client": "workspace:*",
"@temporalio/interceptors-opentelemetry": "workspace:*",
"@temporalio/proto": "workspace:*",
"@temporalio/test-helpers": "workspace:*",
"@temporalio/testing": "workspace:*",
"@temporalio/worker": "workspace:*",
"ai": "^6.0.0",
"ava": "^5.3.1",
"uuid": "^11.1.0",
"zod": "^3.25.76"
},
"engines": {
"node": ">= 20.0.0"
},
Expand All @@ -44,6 +73,8 @@
},
"files": [
"src",
"lib"
"lib",
"!src/__tests__",
"!lib/__tests__"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type {
TranscriptionModelV3,
} from '@ai-sdk/provider';
import { openai } from '@ai-sdk/openai';
import { TestFn } from 'ava';
import { v4 as uuid4 } from 'uuid';
import * as opentelemetry from '@opentelemetry/sdk-node';
import { SEMRESATTRS_SERVICE_NAME } from '@opentelemetry/semantic-conventions';
Expand All @@ -26,7 +27,6 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { experimental_createMCPClient as createMCPClient } from '@ai-sdk/mcp';
import { AiSdkPlugin, createActivities } from '@temporalio/ai-sdk';
import { temporal } from '@temporalio/proto';
import { WorkflowClient } from '@temporalio/client';
import {
Expand All @@ -37,7 +37,12 @@ import {
OpenTelemetryWorkflowClientCallsInterceptor,
OpenTelemetryWorkflowClientInterceptor,
} from '@temporalio/interceptors-opentelemetry';
import { InjectedSinks, Runtime } from '@temporalio/worker';
import { workflowInterceptorModules } from '@temporalio/testing';
import { bundleWorkflowCode, DefaultLogger, InjectedSinks, Runtime } from '@temporalio/worker';

import { test as anyTest, BaseContext, helpers, Worker, TestWorkflowEnvironment } from '@temporalio/test-helpers';

import { AiSdkPlugin, createActivities } from '..';
import {
embeddingWorkflow,
generateObjectWorkflow,
Expand All @@ -48,9 +53,7 @@ import {
telemetryWorkflow,
toolsWorkflow,
} from './workflows/ai-sdk';
import { helpers, makeTestFunction } from './helpers-integration';
import { getWeather } from './activities/ai-sdk';
import { Worker } from './helpers';
import EventType = temporal.api.enums.v1.EventType;

const remoteTests = ['1', 't', 'true'].includes((process.env.AI_SDK_REMOTE_TESTS ?? 'false').toLowerCase());
Expand Down Expand Up @@ -226,8 +229,20 @@ function* embeddingGenerator(): Generator<EmbeddingResponse> {
yield embeddingResponse(['Hello, world!', 'How are you?']);
}

const test = makeTestFunction({
workflowsPath: require.resolve('./workflows/ai-sdk'),
const test = anyTest as TestFn<BaseContext>;

test.before(async (t) => {
const env = await TestWorkflowEnvironment.createLocal();
const workflowBundle = await bundleWorkflowCode({
workflowsPath: require.resolve('./workflows/ai-sdk'),
workflowInterceptorModules,
logger: new DefaultLogger('WARN'),
});
t.context = { env, workflowBundle };
});

test.after.always(async (t) => {
await t.context.env?.teardown();
});

test('Hello world agent responds in haikus', async (t) => {
Expand Down Expand Up @@ -527,7 +542,7 @@ test('callToolActivity awaits tool.execute before closing MCP client', async (t)
}) as Record<string, (args: unknown) => Promise<unknown>>;

// Get the callTool activity
const callToolActivity = activities['testServer-callTool'];
const callToolActivity = activities['testServer-callTool']!;
t.truthy(callToolActivity, 'callToolActivity should exist');

// Call the activity
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Test workflow using AI model
// eslint-disable-next-line import/no-unassigned-import
import '@temporalio/ai-sdk/lib/load-polyfills';
import '../../load-polyfills';
import { embedMany, generateText, Output, stepCountIs, tool, wrapLanguageModel } from 'ai';
import { z } from 'zod';
import type { LanguageModelV3Middleware } from '@ai-sdk/provider';
import { proxyActivities } from '@temporalio/workflow';
import { TemporalMCPClient, temporalProvider } from '@temporalio/ai-sdk';
import { TemporalMCPClient, temporalProvider } from '../..';
import type * as activities from '../activities/ai-sdk';

const { getWeather } = proxyActivities<typeof activities>({
Expand Down Expand Up @@ -126,7 +126,7 @@ export async function mcpSchemaTestWorkflow(): Promise<{
const mcpClient = new TemporalMCPClient({ name: 'testServer' });
const tools = await mcpClient.tools();

const [toolName, tool] = Object.entries(tools)[0];
const [toolName, tool] = Object.entries(tools)[0]!;

const schema = (tool as any).inputSchema.jsonSchema;

Expand Down
14 changes: 14 additions & 0 deletions packages/ai-sdk/src/__tests__/workflows/otel-interceptors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/** Not a workflow, just interceptors */

import { WorkflowInterceptors } from '@temporalio/workflow';
import {
OpenTelemetryInboundInterceptor,
OpenTelemetryOutboundInterceptor,
OpenTelemetryInternalsInterceptor,
} from '@temporalio/interceptors-opentelemetry/lib/workflow';

export const interceptors = (): WorkflowInterceptors => ({
inbound: [new OpenTelemetryInboundInterceptor()],
outbound: [new OpenTelemetryOutboundInterceptor()],
internals: [new OpenTelemetryInternalsInterceptor()],
});
11 changes: 10 additions & 1 deletion packages/ai-sdk/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
"outDir": "./lib",
"rootDir": "./src"
},
"references": [{ "path": "../plugin" }, { "path": "../workflow" }],
"references": [
{ "path": "../plugin" },
{ "path": "../workflow" },
{ "path": "../client" },
{ "path": "../proto" },
{ "path": "../test-helpers" },
{ "path": "../testing" },
{ "path": "../worker" },
{ "path": "../interceptors-opentelemetry" }
],
"include": ["./src/**/*.ts"]
}
4 changes: 3 additions & 1 deletion packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "Temporal.io SDK Client sub-package",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"scripts": {},
"scripts": {
"build": "tsc --build"
},
"keywords": [
"temporal",
"workflow",
Expand Down
4 changes: 3 additions & 1 deletion packages/cloud/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"description": "Temporal.io SDK — Temporal Cloud Client",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"scripts": {},
"scripts": {
"build": "tsc --build"
},
"keywords": [
"temporal",
"workflow",
Expand Down
14 changes: 13 additions & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@
"nexus-rpc": "^0.0.1",
"proto3-json-serializer": "^2.0.0"
},
"scripts": {
"build": "tsc --build",
"test": "ava ./lib/__tests__/test-*.js"
},
"ava": {
"timeout": "60s",
"concurrency": 1,
"workerThreads": false
},
"devDependencies": {
"ava": "^5.3.1",
"protobufjs": "^7.2.5"
},
"bugs": {
Expand All @@ -38,6 +48,8 @@
},
"files": [
"src",
"lib"
"lib",
"!src/__tests__",
"!lib/__tests__"
]
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'ava';
import { coresdk } from '@temporalio/proto';
import { makeProtoEnumConverters as makeProtoEnumConverters } from '@temporalio/common/lib/internal-workflow/enums-helpers';
import { makeProtoEnumConverters as makeProtoEnumConverters } from '../internal-workflow/enums-helpers';

// ASSERTION: There MUST be a corresponding `KEY: 'KEY'` in the const object of strings enum (must be present)
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import test from 'ava';
import { splitProtoHostPort, normalizeGrpcEndpointAddress } from '@temporalio/common/lib/internal-non-workflow';
import { splitProtoHostPort, normalizeGrpcEndpointAddress } from '../internal-non-workflow';

test('splitProtoHostPort', (t) => {
t.deepEqual(splitProtoHostPort('127.0.0.1'), { scheme: undefined, hostname: '127.0.0.1', port: undefined });
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import test from 'ava';
import { compileRetryPolicy, ValueError } from '@temporalio/common';
import { msToTs } from '@temporalio/common/lib/time';
import { compileRetryPolicy, ValueError } from '../index';
import { msToTs } from '../time';

test('compileRetryPolicy validates intervals are not 0', (t) => {
t.throws(() => compileRetryPolicy({ initialInterval: 0 }), {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import test from 'ava';

import Long from 'long';
import { msToTs } from '@temporalio/common/lib/time';
import { msToTs } from '../time';

test('msToTs converts to Timestamp', (t) => {
t.deepEqual({ seconds: Long.fromInt(600), nanos: 0 }, msToTs('10 minutes'));
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import vm from 'vm';
import anyTest, { TestFn } from 'ava';
import { SymbolBasedInstanceOfError } from '@temporalio/common/lib/type-helpers';
import { SymbolBasedInstanceOfError } from '../type-helpers';

interface Context {
cx1: (script: string) => any;
Expand Down
Loading
Loading