mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-10 23:38:27 +00:00
fix: return error in mcp and activity when there are no credits
This commit is contained in:
parent
6732ff71c5
commit
d0126797de
@ -3,6 +3,7 @@ import { IngestionStatus } from "@core/database";
|
||||
import { EpisodeType } from "@core/types";
|
||||
import { type z } from "zod";
|
||||
import { prisma } from "~/db.server";
|
||||
import { hasCredits } from "~/services/billing.server";
|
||||
import { type IngestBodyRequest, ingestTask } from "~/trigger/ingest/ingest";
|
||||
import { ingestDocumentTask } from "~/trigger/ingest/ingest-document";
|
||||
|
||||
@ -27,6 +28,16 @@ export const addToQueue = async (
|
||||
);
|
||||
}
|
||||
|
||||
// Check if workspace has sufficient credits before processing
|
||||
const hasSufficientCredits = await hasCredits(
|
||||
user.Workspace?.id as string,
|
||||
"addEpisode",
|
||||
);
|
||||
|
||||
if (!hasSufficientCredits) {
|
||||
throw new Error("no credits");
|
||||
}
|
||||
|
||||
const queuePersist = await prisma.ingestionQueue.create({
|
||||
data: {
|
||||
data: body,
|
||||
|
||||
@ -75,11 +75,13 @@ const { action, loader } = createActionApiRoute(
|
||||
if (user.Workspace?.id) {
|
||||
try {
|
||||
await triggerWebhookDelivery(activity.id, user.Workspace.id);
|
||||
logger.log("Webhook delivery triggered for activity", { activityId: activity.id });
|
||||
logger.log("Webhook delivery triggered for activity", {
|
||||
activityId: activity.id,
|
||||
});
|
||||
} catch (webhookError) {
|
||||
logger.error("Failed to trigger webhook delivery", {
|
||||
activityId: activity.id,
|
||||
error: webhookError
|
||||
logger.error("Failed to trigger webhook delivery", {
|
||||
activityId: activity.id,
|
||||
error: webhookError,
|
||||
});
|
||||
// Don't fail the entire request if webhook delivery fails
|
||||
}
|
||||
|
||||
@ -6,7 +6,11 @@
|
||||
*/
|
||||
|
||||
import { prisma } from "~/db.server";
|
||||
import { getPlanConfig } from "~/config/billing.server";
|
||||
import {
|
||||
BILLING_CONFIG,
|
||||
getPlanConfig,
|
||||
isBillingEnabled,
|
||||
} from "~/config/billing.server";
|
||||
import type { PlanType, Subscription } from "@prisma/client";
|
||||
|
||||
export type CreditOperation = "addEpisode" | "search" | "chatMessage";
|
||||
@ -221,3 +225,51 @@ export async function getUsageSummary(workspaceId: string) {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if workspace has sufficient credits
|
||||
*/
|
||||
export async function hasCredits(
|
||||
workspaceId: string,
|
||||
operation: CreditOperation,
|
||||
amount?: number,
|
||||
): Promise<boolean> {
|
||||
// If billing is disabled, always return true
|
||||
if (!isBillingEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const creditCost = amount || BILLING_CONFIG.creditCosts[operation];
|
||||
|
||||
const workspace = await prisma.workspace.findUnique({
|
||||
where: { id: workspaceId },
|
||||
include: {
|
||||
Subscription: true,
|
||||
user: {
|
||||
include: {
|
||||
UserUsage: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!workspace?.user?.UserUsage || !workspace.Subscription) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const userUsage = workspace.user.UserUsage;
|
||||
// const subscription = workspace.Subscription;
|
||||
|
||||
// If has available credits, return true
|
||||
if (userUsage.availableCredits >= creditCost) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If overage is enabled (Pro/Max), return true
|
||||
// if (subscription.enableUsageBilling) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// Free plan with no credits left
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -650,6 +650,23 @@ export async function deductCredits(
|
||||
}),
|
||||
]);
|
||||
} else {
|
||||
await prisma.userUsage.update({
|
||||
where: { id: userUsage.id },
|
||||
data: {
|
||||
availableCredits: 0,
|
||||
usedCredits: userUsage.usedCredits + creditCost,
|
||||
// Update usage breakdown
|
||||
...(operation === "addEpisode" && {
|
||||
episodeCreditsUsed: userUsage.episodeCreditsUsed + creditCost,
|
||||
}),
|
||||
...(operation === "search" && {
|
||||
searchCreditsUsed: userUsage.searchCreditsUsed + creditCost,
|
||||
}),
|
||||
...(operation === "chatMessage" && {
|
||||
chatCreditsUsed: userUsage.chatCreditsUsed + creditCost,
|
||||
}),
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,8 @@ import { SearchService } from "~/services/search.server";
|
||||
import { SpaceService } from "~/services/space.server";
|
||||
import { deepSearch } from "~/trigger/deep-search";
|
||||
import { IntegrationLoader } from "./integration-loader";
|
||||
import { hasCredits } from "~/services/billing.server";
|
||||
import { prisma } from "~/db.server";
|
||||
|
||||
const searchService = new SearchService();
|
||||
const spaceService = new SpaceService();
|
||||
@ -277,6 +279,30 @@ async function handleUserProfile(userId: string) {
|
||||
// Handler for memory_ingest
|
||||
async function handleMemoryIngest(args: any) {
|
||||
try {
|
||||
const workspace = await prisma.workspace.findFirst({
|
||||
where: {
|
||||
userId: args.userId,
|
||||
},
|
||||
});
|
||||
|
||||
// Check if workspace has sufficient credits before processing
|
||||
const hasSufficientCredits = await hasCredits(
|
||||
workspace?.id as string,
|
||||
"addEpisode",
|
||||
);
|
||||
|
||||
if (!hasSufficientCredits) {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: "text",
|
||||
text: `Error ingesting data: your credits have expired`,
|
||||
},
|
||||
],
|
||||
isError: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Use spaceIds from args if provided, otherwise use spaceId from query params
|
||||
const spaceIds =
|
||||
args.spaceIds || (args.spaceId ? [args.spaceId] : undefined);
|
||||
|
||||
@ -79,8 +79,8 @@
|
||||
"@tiptap/pm": "^2.11.9",
|
||||
"@tiptap/react": "^2.11.9",
|
||||
"@tiptap/starter-kit": "2.11.9",
|
||||
"@trigger.dev/react-hooks": "4.0.0-v4-beta.22",
|
||||
"@trigger.dev/sdk": "4.0.0-v4-beta.22",
|
||||
"@trigger.dev/react-hooks": "4.0.4",
|
||||
"@trigger.dev/sdk": "4.0.4",
|
||||
"ai": "4.3.19",
|
||||
"axios": "^1.10.0",
|
||||
"bullmq": "^5.53.2",
|
||||
@ -152,7 +152,7 @@
|
||||
"@tailwindcss/forms": "^0.5.10",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tailwindcss/vite": "^4.1.7",
|
||||
"@trigger.dev/build": "4.0.0-v4-beta.22",
|
||||
"@trigger.dev/build": "4.0.4",
|
||||
"@types/compression": "^1.7.2",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/express": "^4.17.13",
|
||||
|
||||
119
pnpm-lock.yaml
generated
119
pnpm-lock.yaml
generated
@ -476,11 +476,11 @@ importers:
|
||||
specifier: 2.11.9
|
||||
version: 2.11.9
|
||||
'@trigger.dev/react-hooks':
|
||||
specifier: 4.0.0-v4-beta.22
|
||||
version: 4.0.0-v4-beta.22(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
'@trigger.dev/sdk':
|
||||
specifier: 4.0.0-v4-beta.22
|
||||
version: 4.0.0-v4-beta.22(ai@4.3.19(react@18.3.1)(zod@3.25.76))(zod@3.25.76)
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4(ai@4.3.19(react@18.3.1)(zod@3.25.76))(zod@3.25.76)
|
||||
ai:
|
||||
specifier: 4.3.19
|
||||
version: 4.3.19(react@18.3.1)(zod@3.25.76)
|
||||
@ -690,8 +690,8 @@ importers:
|
||||
specifier: ^4.1.7
|
||||
version: 4.1.9(vite@6.3.5(@types/node@20.19.7)(jiti@2.4.2)(less@4.4.0)(lightningcss@1.30.1)(sass@1.89.2)(terser@5.42.0)(tsx@4.20.4)(yaml@2.8.0))
|
||||
'@trigger.dev/build':
|
||||
specifier: 4.0.0-v4-beta.22
|
||||
version: 4.0.0-v4-beta.22(typescript@5.8.3)
|
||||
specifier: 4.0.4
|
||||
version: 4.0.4(typescript@5.8.3)
|
||||
'@types/compression':
|
||||
specifier: ^1.7.2
|
||||
version: 1.8.1
|
||||
@ -2863,12 +2863,6 @@ packages:
|
||||
peerDependencies:
|
||||
'@opentelemetry/api': '>=1.0.0 <1.10.0'
|
||||
|
||||
'@opentelemetry/core@1.30.1':
|
||||
resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
'@opentelemetry/api': '>=1.0.0 <1.10.0'
|
||||
|
||||
'@opentelemetry/core@2.0.1':
|
||||
resolution: {integrity: sha512-MaZk9SJIDgo1peKevlbhP6+IwIiNPNmswNL4AF0WaQJLbHXjr9SrZMgS12+iqr9ToV4ZVosCcc0f8Rg67LXjxw==}
|
||||
engines: {node: ^18.19.0 || >=20.6.0}
|
||||
@ -3053,10 +3047,6 @@ packages:
|
||||
resolution: {integrity: sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.28.0':
|
||||
resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.36.0':
|
||||
resolution: {integrity: sha512-TtxJSRD8Ohxp6bKkhrm27JRHAxPczQA7idtcTOMYI+wQRRrfgqxHv1cFbCApcSnNjtXkmzFozn6jQtFrOmbjPQ==}
|
||||
engines: {node: '>=14'}
|
||||
@ -5538,31 +5528,27 @@ packages:
|
||||
'@tiptap/core': ^2.7.0
|
||||
'@tiptap/pm': ^2.7.0
|
||||
|
||||
'@trigger.dev/build@4.0.0-v4-beta.22':
|
||||
resolution: {integrity: sha512-W+SfA7soXzD7f2GQQL2Q4x3+JQkJijcVjgKpNuwPdZcgI++YpJkPzJ5RlT98flErU8ZvuiL26SAur2tvObrZgA==}
|
||||
'@trigger.dev/build@4.0.4':
|
||||
resolution: {integrity: sha512-W3mP+RBkcYOrNYTTmQ/WdU6LB+2Tk1S6r3OjEWqXEPsXLEEw6BzHTHZBirHYX4lWRBL9jVkL+/H74ycyNfzRjg==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@trigger.dev/core@4.0.0-v4-beta.22':
|
||||
resolution: {integrity: sha512-FVaVNsW3KQgYEWStr80Iu+1l4KMyHPVU4QbV55pLQp7d126jOuP+hXYp7LhnYVZtgcQLIZSC0VjJc/UYwr4D6g==}
|
||||
'@trigger.dev/core@4.0.4':
|
||||
resolution: {integrity: sha512-c5myttkNhqaqvLlEz3ttE1qEsULlD6ILBge5FAfEtMv9HVS/pNlgvMKrdFMefaGO/bE4HoxrNGdJsY683Kq32w==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@trigger.dev/core@4.0.0-v4-beta.27':
|
||||
resolution: {integrity: sha512-PJzW07GbxeHKigZ0AiO4aAtDdb2r5iioI7P6TLTqp3XfsxLb1ezPNv3zt6dy1uvZsefGR/EO4y7X0VN1pJyLTA==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
|
||||
'@trigger.dev/react-hooks@4.0.0-v4-beta.22':
|
||||
resolution: {integrity: sha512-hWBoxEkNSM+IcFsUlFEJBcMZGmpaYGPy5k/o+iK9QNLURiQsKEYGYoBzKlA7iP0cVPwhIV1eNlsPediNRQyTsA==}
|
||||
'@trigger.dev/react-hooks@4.0.4':
|
||||
resolution: {integrity: sha512-tgyaGKwFTbVaD4QZdR5GBc2R7T/yq+vHpWw506ys75Mo9uEZN0rGmw7g5q1Pe4XJvsdDiVjcxcJ4tK8zwUM5Zg==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
peerDependencies:
|
||||
react: ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
react-dom: ^18.0 || ^19.0 || ^19.0.0-rc
|
||||
|
||||
'@trigger.dev/sdk@4.0.0-v4-beta.22':
|
||||
resolution: {integrity: sha512-yRv9G/KODpItU16Iv6gCfLQ2SjhGq443zTlYKY3XZf4HHIuByOhkOKYPRpl82FmJprL8DxnT7V0pma4kfHBzPQ==}
|
||||
'@trigger.dev/sdk@4.0.4':
|
||||
resolution: {integrity: sha512-54krRw9SN1CGm5u17JBzu0hNzRf1u37jKbSFFngPJjUOltOgi/owey5+KNu1rGthabhOBK2VKzvKEd4sn08RCA==}
|
||||
engines: {node: '>=18.20.0'}
|
||||
peerDependencies:
|
||||
ai: ^4.2.0
|
||||
zod: ^3.0.0
|
||||
ai: ^4.2.0 || ^5.0.0
|
||||
zod: ^3.0.0 || ^4.0.0
|
||||
peerDependenciesMeta:
|
||||
ai:
|
||||
optional: true
|
||||
@ -8990,10 +8976,6 @@ packages:
|
||||
lodash.defaults@4.2.0:
|
||||
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
|
||||
|
||||
lodash.get@4.4.2:
|
||||
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
|
||||
deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
|
||||
|
||||
lodash.isarguments@3.1.0:
|
||||
resolution: {integrity: sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==}
|
||||
|
||||
@ -15270,11 +15252,6 @@ snapshots:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/semantic-conventions': 1.25.1
|
||||
|
||||
'@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.0)':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/semantic-conventions': 1.28.0
|
||||
|
||||
'@opentelemetry/core@2.0.1(@opentelemetry/api@1.9.0)':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
@ -15524,8 +15501,6 @@ snapshots:
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.25.1': {}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.28.0': {}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.36.0': {}
|
||||
|
||||
'@oslojs/asn1@1.0.0':
|
||||
@ -18414,9 +18389,9 @@ snapshots:
|
||||
'@tiptap/core': 2.25.0(@tiptap/pm@2.25.0)
|
||||
'@tiptap/pm': 2.25.0
|
||||
|
||||
'@trigger.dev/build@4.0.0-v4-beta.22(typescript@5.8.3)':
|
||||
'@trigger.dev/build@4.0.4(typescript@5.8.3)':
|
||||
dependencies:
|
||||
'@trigger.dev/core': 4.0.0-v4-beta.22
|
||||
'@trigger.dev/core': 4.0.4
|
||||
pkg-types: 1.3.1
|
||||
tinyglobby: 0.2.14
|
||||
tsconfck: 3.1.3(typescript@5.8.3)
|
||||
@ -18426,46 +18401,7 @@ snapshots:
|
||||
- typescript
|
||||
- utf-8-validate
|
||||
|
||||
'@trigger.dev/core@4.0.0-v4-beta.22':
|
||||
dependencies:
|
||||
'@bugsnag/cuid': 3.2.1
|
||||
'@electric-sql/client': 1.0.0-beta.1
|
||||
'@google-cloud/precise-date': 4.0.0
|
||||
'@jsonhero/path': 1.0.21
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/api-logs': 0.52.1
|
||||
'@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/exporter-logs-otlp-http': 0.52.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/exporter-trace-otlp-http': 0.52.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/instrumentation': 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0)
|
||||
'@opentelemetry/resources': 1.25.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/sdk-logs': 0.52.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/sdk-node': 0.52.1(@opentelemetry/api@1.9.0)(supports-color@10.0.0)
|
||||
'@opentelemetry/sdk-trace-base': 1.25.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/sdk-trace-node': 1.25.1(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/semantic-conventions': 1.25.1
|
||||
dequal: 2.0.3
|
||||
eventsource: 3.0.7
|
||||
eventsource-parser: 3.0.3
|
||||
execa: 8.0.1
|
||||
humanize-duration: 3.33.0
|
||||
jose: 5.10.0
|
||||
nanoid: 3.3.8
|
||||
prom-client: 15.1.3
|
||||
socket.io: 4.7.4
|
||||
socket.io-client: 4.7.5
|
||||
std-env: 3.9.0
|
||||
superjson: 2.2.2
|
||||
tinyexec: 0.3.2
|
||||
zod: 3.23.8
|
||||
zod-error: 1.5.0
|
||||
zod-validation-error: 1.5.0(zod@3.23.8)
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@trigger.dev/core@4.0.0-v4-beta.27':
|
||||
'@trigger.dev/core@4.0.4':
|
||||
dependencies:
|
||||
'@bugsnag/cuid': 3.2.1
|
||||
'@electric-sql/client': 1.0.0-beta.1
|
||||
@ -18488,7 +18424,6 @@ snapshots:
|
||||
execa: 8.0.1
|
||||
humanize-duration: 3.33.0
|
||||
jose: 5.10.0
|
||||
lodash.get: 4.4.2
|
||||
nanoid: 3.3.8
|
||||
prom-client: 15.1.3
|
||||
socket.io: 4.7.4
|
||||
@ -18505,9 +18440,9 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@trigger.dev/react-hooks@4.0.0-v4-beta.22(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
'@trigger.dev/react-hooks@4.0.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)':
|
||||
dependencies:
|
||||
'@trigger.dev/core': 4.0.0-v4-beta.27
|
||||
'@trigger.dev/core': 4.0.4
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
swr: 2.3.3(react@18.3.1)
|
||||
@ -18516,15 +18451,14 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@trigger.dev/sdk@4.0.0-v4-beta.22(ai@4.3.19(react@18.3.1)(zod@3.25.76))(zod@3.25.76)':
|
||||
'@trigger.dev/sdk@4.0.4(ai@4.3.19(react@18.3.1)(zod@3.25.76))(zod@3.25.76)':
|
||||
dependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@opentelemetry/api-logs': 0.52.1
|
||||
'@opentelemetry/semantic-conventions': 1.25.1
|
||||
'@trigger.dev/core': 4.0.0-v4-beta.22
|
||||
'@opentelemetry/semantic-conventions': 1.36.0
|
||||
'@trigger.dev/core': 4.0.4
|
||||
chalk: 5.4.1
|
||||
cronstrue: 2.59.0
|
||||
debug: 4.4.1(supports-color@10.0.0)
|
||||
debug: 4.4.3
|
||||
evt: 2.5.9
|
||||
slug: 6.1.0
|
||||
ulid: 2.4.0
|
||||
@ -20393,7 +20327,6 @@ snapshots:
|
||||
debug@4.4.3:
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
optional: true
|
||||
|
||||
decamelize-keys@1.1.1:
|
||||
dependencies:
|
||||
@ -22568,8 +22501,6 @@ snapshots:
|
||||
|
||||
lodash.defaults@4.2.0: {}
|
||||
|
||||
lodash.get@4.4.2: {}
|
||||
|
||||
lodash.isarguments@3.1.0: {}
|
||||
|
||||
lodash.isplainobject@4.0.6: {}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user