diff --git a/.github/workflows/auto-test-publish.yml b/.github/workflows/auto-test-publish.yml index 0b04b680f..9aeaabb2f 100644 --- a/.github/workflows/auto-test-publish.yml +++ b/.github/workflows/auto-test-publish.yml @@ -27,7 +27,7 @@ jobs: fetch-depth: 0 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 @@ -84,10 +84,17 @@ jobs: PACKAGE_NAME=$(node -p "require('./package.json').name") PACKAGE_VERSION=$(node -p "require('./package.json').version") - echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." - pnpm publish --access public --tag test --no-git-checks - echo "published=true" >> $GITHUB_OUTPUT - echo "✅ Successfully published $PACKAGE_NAME to test tag" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "🔍 Validating $PACKAGE_NAME@$PACKAGE_VERSION with publish dry-run..." + pnpm publish --dry-run --access public --tag test --no-git-checks + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Successfully validated $PACKAGE_NAME publish" + else + echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." + pnpm publish --access public --tag test --no-git-checks + echo "published=true" >> $GITHUB_OUTPUT + echo "✅ Successfully published $PACKAGE_NAME to test tag" + fi # React SDK - name: Version and build React SDK @@ -126,10 +133,17 @@ jobs: PACKAGE_NAME=$(node -p "require('./package.json').name") PACKAGE_VERSION=$(node -p "require('./package.json').version") - echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." - pnpm publish --access public --tag test --no-git-checks - echo "published=true" >> $GITHUB_OUTPUT - echo "✅ Successfully published $PACKAGE_NAME to test tag" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "🔍 Validating $PACKAGE_NAME@$PACKAGE_VERSION with publish dry-run..." + pnpm publish --dry-run --access public --tag test --no-git-checks + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Successfully validated $PACKAGE_NAME publish" + else + echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." + pnpm publish --access public --tag test --no-git-checks + echo "published=true" >> $GITHUB_OUTPUT + echo "✅ Successfully published $PACKAGE_NAME to test tag" + fi # Next.js SDK - name: Version and build Next.js SDK @@ -168,10 +182,17 @@ jobs: PACKAGE_NAME=$(node -p "require('./package.json').name") PACKAGE_VERSION=$(node -p "require('./package.json').version") - echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." - pnpm publish --access public --tag test --no-git-checks - echo "published=true" >> $GITHUB_OUTPUT - echo "✅ Successfully published $PACKAGE_NAME to test tag" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "🔍 Validating $PACKAGE_NAME@$PACKAGE_VERSION with publish dry-run..." + pnpm publish --dry-run --access public --tag test --no-git-checks + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Successfully validated $PACKAGE_NAME publish" + else + echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." + pnpm publish --access public --tag test --no-git-checks + echo "published=true" >> $GITHUB_OUTPUT + echo "✅ Successfully published $PACKAGE_NAME to test tag" + fi # AIx402 SDK - name: Version and build AIx402 SDK @@ -210,10 +231,17 @@ jobs: PACKAGE_NAME=$(node -p "require('./package.json').name") PACKAGE_VERSION=$(node -p "require('./package.json').version") - echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." - pnpm publish --access public --tag test --no-git-checks - echo "published=true" >> $GITHUB_OUTPUT - echo "✅ Successfully published $PACKAGE_NAME to test tag" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "🔍 Validating $PACKAGE_NAME@$PACKAGE_VERSION with publish dry-run..." + pnpm publish --dry-run --access public --tag test --no-git-checks + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Successfully validated $PACKAGE_NAME publish" + else + echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." + pnpm publish --access public --tag test --no-git-checks + echo "published=true" >> $GITHUB_OUTPUT + echo "✅ Successfully published $PACKAGE_NAME to test tag" + fi # Echo Start CLI - name: Version and build Echo Start CLI @@ -252,15 +280,26 @@ jobs: PACKAGE_NAME=$(node -p "require('./package.json').name") PACKAGE_VERSION=$(node -p "require('./package.json').version") - echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." - pnpm publish --access public --tag test --no-git-checks - echo "published=true" >> $GITHUB_OUTPUT - echo "✅ Successfully published $PACKAGE_NAME to test tag" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "🔍 Validating $PACKAGE_NAME@$PACKAGE_VERSION with publish dry-run..." + pnpm publish --dry-run --access public --tag test --no-git-checks + echo "published=false" >> $GITHUB_OUTPUT + echo "✅ Successfully validated $PACKAGE_NAME publish" + else + echo "🚀 Publishing $PACKAGE_NAME@$PACKAGE_VERSION to test tag..." + pnpm publish --access public --tag test --no-git-checks + echo "published=true" >> $GITHUB_OUTPUT + echo "✅ Successfully published $PACKAGE_NAME to test tag" + fi - name: Summary run: | - echo "✅ Test version published successfully!" + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "✅ Test version validated successfully!" + else + echo "✅ Test version published successfully!" + fi echo "📦 Version: ${{ steps.get-version.outputs.version }}" echo "🏷️ Tag: test" echo "" - echo "Install with: npm install @merit-systems/echo-typescript-sdk@test" \ No newline at end of file + echo "Install with: npm install @merit-systems/echo-typescript-sdk@test" diff --git a/.github/workflows/ci-checks.yml b/.github/workflows/ci-checks.yml index 8b6bb6be0..5a656ef2d 100644 --- a/.github/workflows/ci-checks.yml +++ b/.github/workflows/ci-checks.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v4 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index eeed97615..fe123590e 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -100,7 +100,7 @@ jobs: uses: actions/checkout@v4 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 @@ -378,7 +378,7 @@ jobs: uses: actions/checkout@v4 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/provider-smoke-tests.yml b/.github/workflows/provider-smoke-tests.yml index 2869ff26c..54d0938e2 100644 --- a/.github/workflows/provider-smoke-tests.yml +++ b/.github/workflows/provider-smoke-tests.yml @@ -21,7 +21,7 @@ jobs: uses: actions/checkout@v4 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/publish-sdks.yml b/.github/workflows/publish-sdks.yml index e5796625d..b058420c1 100644 --- a/.github/workflows/publish-sdks.yml +++ b/.github/workflows/publish-sdks.yml @@ -32,7 +32,7 @@ jobs: fetch-depth: 0 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/.github/workflows/test-publish.yml b/.github/workflows/test-publish.yml index 4a2cb96d4..d576b7a4a 100644 --- a/.github/workflows/test-publish.yml +++ b/.github/workflows/test-publish.yml @@ -94,7 +94,7 @@ jobs: fetch-depth: 0 - name: Install pnpm - run: npm install -g pnpm + run: npm install -g pnpm@10.11.0 - name: Setup Node.js uses: actions/setup-node@v4 diff --git a/packages/sdk/next/package.json b/packages/sdk/next/package.json index 93ecbc6f3..fdba1d1c0 100644 --- a/packages/sdk/next/package.json +++ b/packages/sdk/next/package.json @@ -1,6 +1,6 @@ { "name": "@merit-systems/echo-next-sdk", - "version": "0.0.30", + "version": "0.0.31", "description": "Next.js SDK for Echo", "type": "module", "main": "./dist/index.js", diff --git a/packages/sdk/react/package.json b/packages/sdk/react/package.json index 5e409476f..ffccd9655 100644 --- a/packages/sdk/react/package.json +++ b/packages/sdk/react/package.json @@ -1,6 +1,6 @@ { "name": "@merit-systems/echo-react-sdk", - "version": "1.0.39", + "version": "1.0.40", "description": "React SDK for Echo OAuth2 + PKCE authentication and token management", "type": "module", "main": "./dist/index.cjs", diff --git a/packages/sdk/ts/package.json b/packages/sdk/ts/package.json index f2a7f1066..864d51ea9 100644 --- a/packages/sdk/ts/package.json +++ b/packages/sdk/ts/package.json @@ -1,6 +1,6 @@ { "name": "@merit-systems/echo-typescript-sdk", - "version": "1.0.23", + "version": "1.0.24", "description": "TypeScript SDK for Echo platform", "type": "module", "main": "./dist/index.cjs", diff --git a/packages/sdk/ts/src/supported-models/chat/anthropic.ts b/packages/sdk/ts/src/supported-models/chat/anthropic.ts index de039a1fc..e6fb9c6c7 100644 --- a/packages/sdk/ts/src/supported-models/chat/anthropic.ts +++ b/packages/sdk/ts/src/supported-models/chat/anthropic.ts @@ -11,8 +11,10 @@ export type AnthropicModel = | 'claude-haiku-4-5-20251001' | 'claude-opus-4-1-20250805' | 'claude-opus-4-20250514' + | 'claude-opus-4-8' | 'claude-sonnet-4-20250514' - | 'claude-sonnet-4-5-20250929'; + | 'claude-sonnet-4-5-20250929' + | 'claude-sonnet-4-6'; export const AnthropicModels: SupportedModel[] = [ { @@ -69,6 +71,12 @@ export const AnthropicModels: SupportedModel[] = [ output_cost_per_token: 0.000075, provider: 'Anthropic', }, + { + model_id: 'claude-opus-4-8', + input_cost_per_token: 0.000005, + output_cost_per_token: 0.000025, + provider: 'Anthropic', + }, { model_id: 'claude-sonnet-4-20250514', input_cost_per_token: 0.000003, @@ -81,4 +89,10 @@ export const AnthropicModels: SupportedModel[] = [ output_cost_per_token: 0.000015, provider: 'Anthropic', }, + { + model_id: 'claude-sonnet-4-6', + input_cost_per_token: 0.000003, + output_cost_per_token: 0.000015, + provider: 'Anthropic', + }, ]; diff --git a/packages/sdk/ts/src/supported-models/chat/openrouter.ts b/packages/sdk/ts/src/supported-models/chat/openrouter.ts index 0c07dbd2d..20d08b2e9 100644 --- a/packages/sdk/ts/src/supported-models/chat/openrouter.ts +++ b/packages/sdk/ts/src/supported-models/chat/openrouter.ts @@ -26,8 +26,10 @@ export type OpenRouterModel = | 'anthropic/claude-haiku-4.5' | 'anthropic/claude-opus-4' | 'anthropic/claude-opus-4.1' + | 'anthropic/claude-opus-4.8' | 'anthropic/claude-sonnet-4' | 'anthropic/claude-sonnet-4.5' + | 'anthropic/claude-sonnet-4.6' | 'arcee-ai/afm-4.5b' | 'arcee-ai/coder-large' | 'arcee-ai/maestro-reasoning' @@ -421,6 +423,12 @@ export const OpenRouterModels: SupportedModel[] = [ output_cost_per_token: 0.000075, provider: 'OpenRouter', }, + { + model_id: 'anthropic/claude-opus-4.8', + input_cost_per_token: 0.000005, + output_cost_per_token: 0.000025, + provider: 'OpenRouter', + }, { model_id: 'anthropic/claude-sonnet-4', input_cost_per_token: 0.000003, @@ -433,6 +441,12 @@ export const OpenRouterModels: SupportedModel[] = [ output_cost_per_token: 0.000015, provider: 'OpenRouter', }, + { + model_id: 'anthropic/claude-sonnet-4.6', + input_cost_per_token: 0.000003, + output_cost_per_token: 0.000015, + provider: 'OpenRouter', + }, { model_id: 'arcee-ai/afm-4.5b', input_cost_per_token: 4.8e-8, diff --git a/packages/tests/integration/tests/echo-data-server/api-key.client.test.ts b/packages/tests/integration/tests/echo-data-server/api-key.client.test.ts index 7ef68bf8f..86156eeaf 100644 --- a/packages/tests/integration/tests/echo-data-server/api-key.client.test.ts +++ b/packages/tests/integration/tests/echo-data-server/api-key.client.test.ts @@ -2,6 +2,7 @@ import { TEST_CONFIG } from '@/config/test-config'; import { describe, test, expect } from 'vitest'; import { TEST_CLIENT_IDS, TEST_USER_API_KEYS } from '@/config/test-data'; import { echoControlApi } from '@/utils/api-client'; +import { waitForBalanceUpdate } from '@/utils/balance-helpers'; import OpenAI from 'openai'; describe('API Key Client', () => { @@ -39,9 +40,10 @@ describe('API Key Client', () => { expect(chunkCount).toBeGreaterThan(0); expect(receivedContent.length).toBeGreaterThan(0); - // await new Promise(resolve => setTimeout(resolve, 1000)); /// TODO BEN REALLY TODO: SPEED UP THE BALANCE UPDATE SO WE DON'T HAVE TO WAIT FOR 2 SECONDS - - const secondBalanceCheck = await echoControlApi.getBalance(apiKey); + const secondBalanceCheck = await waitForBalanceUpdate( + () => echoControlApi.getBalance(apiKey), + balanceCheck + ); console.log('🔄 Second balance check: ', secondBalanceCheck); expect(secondBalanceCheck.totalPaid).toBe(balanceCheck.totalPaid); @@ -76,7 +78,10 @@ describe('API Key Client', () => { expect(completion.choices).toBeDefined(); expect(completion.choices[0]?.message?.content).toBeDefined(); - const secondBalanceCheck = await echoControlApi.getBalance(apiKey); + const secondBalanceCheck = await waitForBalanceUpdate( + () => echoControlApi.getBalance(apiKey), + balanceCheck + ); expect(secondBalanceCheck.totalPaid).toBe(balanceCheck.totalPaid); expect(secondBalanceCheck.totalSpent).toBeGreaterThanOrEqual( balanceCheck.totalSpent diff --git a/packages/tests/integration/tests/echo-data-server/echo-access-jwt.client.test.ts b/packages/tests/integration/tests/echo-data-server/echo-access-jwt.client.test.ts index 08447e909..65cc63022 100644 --- a/packages/tests/integration/tests/echo-data-server/echo-access-jwt.client.test.ts +++ b/packages/tests/integration/tests/echo-data-server/echo-access-jwt.client.test.ts @@ -4,6 +4,7 @@ import { TEST_CONFIG, echoControlApi, TEST_CLIENT_IDS, + waitForBalanceUpdate, } from '../../utils/index.js'; import { EchoControlApiClient } from '../../utils/api-client.js'; @@ -178,8 +179,9 @@ describe('Echo Data Server Client Integration Tests', () => { accessToken = await getAccessTokenForPaidUser(); - const secondBalanceCheck = await echoControlApi.getBalance( - accessToken.access_token + const secondBalanceCheck = await waitForBalanceUpdate( + () => echoControlApi.getBalance(accessToken.access_token), + balanceCheck ); expect(secondBalanceCheck.totalPaid).toBe(balanceCheck.totalPaid); expect(secondBalanceCheck.totalSpent).toBeGreaterThan( @@ -233,8 +235,9 @@ describe('Echo Data Server Client Integration Tests', () => { accessToken = await getAccessTokenForPaidUser(); - const secondBalanceCheck = await echoControlApi.getBalance( - accessToken.access_token + const secondBalanceCheck = await waitForBalanceUpdate( + () => echoControlApi.getBalance(accessToken.access_token), + balanceCheck ); expect(secondBalanceCheck.totalPaid).toBe(balanceCheck.totalPaid); expect(secondBalanceCheck.totalSpent).toBeGreaterThan( diff --git a/packages/tests/integration/utils/balance-helpers.ts b/packages/tests/integration/utils/balance-helpers.ts new file mode 100644 index 000000000..b86bbfe39 --- /dev/null +++ b/packages/tests/integration/utils/balance-helpers.ts @@ -0,0 +1,41 @@ +export interface BalanceSnapshot { + totalPaid: number; + totalSpent: number; + balance: number; +} + +interface WaitForBalanceUpdateOptions { + timeoutMs?: number; + intervalMs?: number; +} + +const sleep = (ms: number) => new Promise(resolve => setTimeout(resolve, ms)); + +export async function waitForBalanceUpdate( + getBalance: () => Promise, + initialBalance: BalanceSnapshot, + options: WaitForBalanceUpdateOptions = {} +): Promise { + const timeoutMs = options.timeoutMs ?? 5000; + const intervalMs = options.intervalMs ?? 250; + const deadline = Date.now() + timeoutMs; + let latestBalance = await getBalance(); + + while (Date.now() < deadline) { + if ( + latestBalance.totalSpent > initialBalance.totalSpent || + latestBalance.balance < initialBalance.balance + ) { + return latestBalance; + } + + await sleep(intervalMs); + latestBalance = await getBalance(); + } + + throw new Error( + `Balance did not update within ${timeoutMs}ms. Initial: ${JSON.stringify( + initialBalance + )}. Latest: ${JSON.stringify(latestBalance)}.` + ); +} diff --git a/packages/tests/integration/utils/index.ts b/packages/tests/integration/utils/index.ts index ea8925f4b..466aac6e5 100644 --- a/packages/tests/integration/utils/index.ts +++ b/packages/tests/integration/utils/index.ts @@ -4,6 +4,7 @@ export * from './api-client'; export * from './auth-helpers'; export * from './test-data-factory'; export * from './browser-helpers'; +export * from './balance-helpers'; // Re-export configuration and test data export * from '../config/index.js'; diff --git a/templates/assistant-ui/package.json b/templates/assistant-ui/package.json index 418276960..621e3d748 100644 --- a/templates/assistant-ui/package.json +++ b/templates/assistant-ui/package.json @@ -7,7 +7,7 @@ "@ai-sdk/openai": "2.0.16", "@ai-sdk/react": "2.0.17", "@assistant-ui/react": "^0.11.3", - "@assistant-ui/react-ai-sdk": "^1.1.0", + "@assistant-ui/react-ai-sdk": "1.1.0", "@assistant-ui/react-markdown": "^0.11.0", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-tooltip": "^1.2.8",