mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-10 23:48:26 +00:00
fix: streaming
This commit is contained in:
parent
6a05ea4f37
commit
c1ccb2bb23
@ -10,6 +10,15 @@ interface AIConversationItemProps {
|
||||
message: UIMessage;
|
||||
}
|
||||
|
||||
function getMessage(message: string) {
|
||||
let finalMessage = message.replace("<final_response>", "");
|
||||
finalMessage = finalMessage.replace("</final_response>", "");
|
||||
finalMessage = finalMessage.replace("<question_response>", "");
|
||||
finalMessage = finalMessage.replace("</question_response>", "");
|
||||
|
||||
return finalMessage;
|
||||
}
|
||||
|
||||
const ConversationItemComponent = ({ message }: AIConversationItemProps) => {
|
||||
const isUser = message.role === "user" || false;
|
||||
const textPart = message.parts.find((part) => part.type === "text");
|
||||
@ -17,12 +26,12 @@ const ConversationItemComponent = ({ message }: AIConversationItemProps) => {
|
||||
const editor = useEditor({
|
||||
extensions: [...extensionsForConversation, skillExtension],
|
||||
editable: false,
|
||||
content: textPart ? textPart.text : "",
|
||||
content: textPart ? getMessage(textPart.text) : "",
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (textPart) {
|
||||
editor?.commands.setContent(textPart.text);
|
||||
editor?.commands.setContent(getMessage(textPart.text));
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [message]);
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
import { StopCondition, tool } from "ai";
|
||||
import z from "zod";
|
||||
import { type StopCondition } from "ai";
|
||||
|
||||
export const hasAnswer: StopCondition<any> = ({ steps }) => {
|
||||
return (
|
||||
@ -9,8 +8,7 @@ export const hasAnswer: StopCondition<any> = ({ steps }) => {
|
||||
|
||||
export const hasQuestion: StopCondition<any> = ({ steps }) => {
|
||||
return (
|
||||
steps.some((step) => step.text?.includes("</question_response>")) ??
|
||||
false
|
||||
steps.some((step) => step.text?.includes("</question_response>")) ?? false
|
||||
);
|
||||
};
|
||||
|
||||
@ -163,19 +161,6 @@ CRITICAL:
|
||||
</communication>
|
||||
`;
|
||||
|
||||
export const fixedTools = {
|
||||
progressUpdate: tool({
|
||||
description:
|
||||
"Send a progress update to the user about what has been discovered or will be done next in a crisp and user friendly way no technical terms",
|
||||
inputSchema: z.object({
|
||||
message: z.string(),
|
||||
}),
|
||||
execute: async ({ message }: { message: string }) => ({
|
||||
message,
|
||||
}),
|
||||
}),
|
||||
};
|
||||
|
||||
export function getReActPrompt(
|
||||
metadata?: { source?: string; url?: string; pageTitle?: string },
|
||||
intentOverride?: string,
|
||||
|
||||
@ -15,6 +15,7 @@ import type { z } from "zod";
|
||||
import type { IngestBodyRequest } from "~/jobs/ingest/ingest-episode.logic";
|
||||
import type { CreateConversationTitlePayload } from "~/jobs/conversation/create-title.logic";
|
||||
import type { SessionCompactionPayload } from "~/jobs/session/session-compaction.logic";
|
||||
import { type SpaceAssignmentPayload } from "~/trigger/spaces/space-assignment";
|
||||
|
||||
type QueueProvider = "trigger" | "bullmq";
|
||||
|
||||
@ -145,12 +146,9 @@ export async function enqueueSessionCompaction(
|
||||
* Enqueue space assignment job
|
||||
* (Helper for common job logic to call)
|
||||
*/
|
||||
export async function enqueueSpaceAssignment(payload: {
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
mode: "episode";
|
||||
episodeIds: string[];
|
||||
}): Promise<void> {
|
||||
export async function enqueueSpaceAssignment(
|
||||
payload: SpaceAssignmentPayload,
|
||||
): Promise<void> {
|
||||
const provider = env.QUEUE_PROVIDER as QueueProvider;
|
||||
|
||||
if (provider === "trigger") {
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
experimental_createMCPClient as createMCPClient,
|
||||
generateId,
|
||||
stepCountIs,
|
||||
StopCondition,
|
||||
} from "ai";
|
||||
import { z } from "zod";
|
||||
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
||||
@ -21,7 +20,11 @@ import { getModel } from "~/lib/model.server";
|
||||
import { UserTypeEnum } from "@core/types";
|
||||
import { nanoid } from "nanoid";
|
||||
import { getOrCreatePersonalAccessToken } from "~/services/personalAccessToken.server";
|
||||
import { hasAnswer, hasQuestion, REACT_SYSTEM_PROMPT } from "~/lib/prompt.server";
|
||||
import {
|
||||
hasAnswer,
|
||||
hasQuestion,
|
||||
REACT_SYSTEM_PROMPT,
|
||||
} from "~/lib/prompt.server";
|
||||
import { enqueueCreateConversationTitle } from "~/lib/queue-adapter.server";
|
||||
import { env } from "~/env.server";
|
||||
|
||||
@ -109,8 +112,6 @@ const { loader, action } = createHybridActionApiRoute(
|
||||
messages: finalMessages,
|
||||
});
|
||||
|
||||
|
||||
|
||||
const result = streamText({
|
||||
model: getModel() as LanguageModel,
|
||||
messages: [
|
||||
@ -121,7 +122,7 @@ const { loader, action } = createHybridActionApiRoute(
|
||||
...convertToModelMessages(validatedMessages),
|
||||
],
|
||||
tools,
|
||||
stopWhen: [stepCountIs(10), hasAnswer,hasQuestion],
|
||||
stopWhen: [stepCountIs(10), hasAnswer, hasQuestion],
|
||||
});
|
||||
|
||||
result.consumeStream(); // no await
|
||||
@ -129,7 +130,6 @@ const { loader, action } = createHybridActionApiRoute(
|
||||
return result.toUIMessageStreamResponse({
|
||||
originalMessages: validatedMessages,
|
||||
onFinish: async ({ messages }) => {
|
||||
console.log(JSON.stringify(messages));
|
||||
const lastMessage = messages.pop();
|
||||
let message = "";
|
||||
lastMessage?.parts.forEach((part) => {
|
||||
|
||||
@ -10,7 +10,6 @@ import {
|
||||
|
||||
import {
|
||||
convertToModelMessages,
|
||||
type CoreMessage,
|
||||
generateId,
|
||||
generateText,
|
||||
type LanguageModel,
|
||||
@ -109,11 +108,17 @@ const { action, loader } = createActionApiRoute(
|
||||
const tools = {
|
||||
searchMemory: searchTool,
|
||||
};
|
||||
|
||||
// Build initial messages with ReAct prompt
|
||||
const initialMessages = [
|
||||
{
|
||||
role: "user",
|
||||
parts: [{ type: "text", text: `CONTENT TO ANALYZE:\n${body.content}\n\nPlease search my memory for relevant context and synthesize what you find.` }],
|
||||
parts: [
|
||||
{
|
||||
type: "text",
|
||||
text: `CONTENT TO ANALYZE:\n${body.content}\n\nPlease search my memory for relevant context and synthesize what you find.`,
|
||||
},
|
||||
],
|
||||
id: generateId(),
|
||||
},
|
||||
];
|
||||
@ -134,7 +139,7 @@ const { action, loader } = createActionApiRoute(
|
||||
...convertToModelMessages(validatedMessages),
|
||||
],
|
||||
tools,
|
||||
stopWhen: [stepCountIs(10), hasAnswer],
|
||||
stopWhen: [hasAnswer, stepCountIs(10)],
|
||||
});
|
||||
|
||||
return result.toUIMessageStreamResponse({
|
||||
@ -151,7 +156,7 @@ const { action, loader } = createActionApiRoute(
|
||||
...convertToModelMessages(validatedMessages),
|
||||
],
|
||||
tools,
|
||||
stopWhen: [stepCountIs(10), hasAnswer],
|
||||
stopWhen: [hasAnswer, stepCountIs(10)],
|
||||
});
|
||||
|
||||
await deletePersonalAccessToken(pat?.id);
|
||||
|
||||
@ -3,7 +3,7 @@ import { createHybridActionApiRoute } from "~/services/routeBuilders/apiBuilder.
|
||||
import { SpaceService } from "~/services/space.server";
|
||||
import { json } from "@remix-run/node";
|
||||
import { logger } from "~/services/logger.service";
|
||||
import { triggerSpaceAssignment } from "~/trigger/spaces/space-assignment";
|
||||
import { enqueueSpaceAssignment } from "~/lib/queue-adapter.server";
|
||||
|
||||
// Schema for space ID parameter
|
||||
const SpaceParamsSchema = z.object({
|
||||
@ -31,7 +31,7 @@ const { loader, action } = createHybridActionApiRoute(
|
||||
|
||||
// Trigger automatic episode assignment for the reset space
|
||||
try {
|
||||
await triggerSpaceAssignment({
|
||||
await enqueueSpaceAssignment({
|
||||
userId: userId,
|
||||
workspaceId: space.workspaceId,
|
||||
mode: "new_space",
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
import { z } from "zod";
|
||||
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
|
||||
import { json } from "@remix-run/node";
|
||||
import { triggerSpaceAssignment } from "~/trigger/spaces/space-assignment";
|
||||
import { prisma } from "~/db.server";
|
||||
import { enqueueSpaceAssignment } from "~/lib/queue-adapter.server";
|
||||
|
||||
// Schema for manual assignment trigger
|
||||
const ManualAssignmentSchema = z.object({
|
||||
@ -38,7 +38,7 @@ const { action } = createActionApiRoute(
|
||||
let taskRun;
|
||||
|
||||
// Direct LLM assignment trigger
|
||||
taskRun = await triggerSpaceAssignment({
|
||||
taskRun = await enqueueSpaceAssignment({
|
||||
userId,
|
||||
workspaceId: user?.Workspace?.id as string,
|
||||
mode: body.mode,
|
||||
@ -49,7 +49,7 @@ const { action } = createActionApiRoute(
|
||||
return json({
|
||||
success: true,
|
||||
message: `${body.mode} assignment task triggered successfully`,
|
||||
taskId: taskRun.id,
|
||||
|
||||
payload: {
|
||||
userId,
|
||||
mode: body.mode,
|
||||
|
||||
@ -55,9 +55,10 @@ export default function SingleConversation() {
|
||||
},
|
||||
}),
|
||||
});
|
||||
console.log("new", messages);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (conversation.ConversationHistory.length === 1) {
|
||||
if (messages.length === 1) {
|
||||
regenerate();
|
||||
}
|
||||
}, []);
|
||||
@ -96,7 +97,7 @@ export default function SingleConversation() {
|
||||
<div className="w-full max-w-[80ch] px-1 pr-2">
|
||||
<ConversationTextarea
|
||||
className="bg-background-3 w-full border-1 border-gray-300"
|
||||
isLoading={status === "streaming"}
|
||||
isLoading={status === "streaming" || status === "submitted"}
|
||||
onConversationCreated={(message) => {
|
||||
if (message) {
|
||||
sendMessage({ text: message });
|
||||
|
||||
@ -6,7 +6,6 @@ import {
|
||||
} from "@core/types";
|
||||
import { type Space } from "@prisma/client";
|
||||
|
||||
import { triggerSpaceAssignment } from "~/trigger/spaces/space-assignment";
|
||||
import {
|
||||
assignEpisodesToSpace,
|
||||
createSpace,
|
||||
@ -18,6 +17,7 @@ import {
|
||||
} from "./graphModels/space";
|
||||
import { prisma } from "~/trigger/utils/prisma";
|
||||
import { trackFeatureUsage } from "./telemetry.server";
|
||||
import { enqueueSpaceAssignment } from "~/lib/queue-adapter.server";
|
||||
|
||||
export class SpaceService {
|
||||
/**
|
||||
@ -69,7 +69,7 @@ export class SpaceService {
|
||||
|
||||
// Trigger automatic LLM assignment for the new space
|
||||
try {
|
||||
await triggerSpaceAssignment({
|
||||
await enqueueSpaceAssignment({
|
||||
userId: params.userId,
|
||||
workspaceId: params.workspaceId,
|
||||
mode: "new_space",
|
||||
|
||||
@ -128,6 +128,7 @@ export async function trackEvent(
|
||||
modelProvider: getModelProvider(),
|
||||
embeddingModel: env.EMBEDDING_MODEL,
|
||||
appEnv: env.APP_ENV,
|
||||
appOrigin: env.APP_ORIGIN,
|
||||
timestamp: new Date().toISOString(),
|
||||
};
|
||||
|
||||
@ -175,6 +176,7 @@ export async function trackFeatureUsage(
|
||||
event: feature,
|
||||
properties: {
|
||||
...properties,
|
||||
appOrigin: env.APP_ORIGIN,
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
});
|
||||
@ -204,6 +206,7 @@ export async function trackConfig(): Promise<void> {
|
||||
appEnv: env.APP_ENV,
|
||||
nodeEnv: env.NODE_ENV,
|
||||
timestamp: new Date().toISOString(),
|
||||
appOrigin: env.APP_ORIGIN,
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
@ -231,6 +234,7 @@ export async function trackError(
|
||||
properties: {
|
||||
errorType: error.name,
|
||||
errorMessage: error.message,
|
||||
appOrigin: env.APP_ORIGIN,
|
||||
stackTrace: error.stack,
|
||||
...context,
|
||||
timestamp: new Date().toISOString(),
|
||||
|
||||
@ -18,7 +18,7 @@ import type { CoreMessage } from "ai";
|
||||
import { z } from "zod";
|
||||
import { type Space } from "@prisma/client";
|
||||
|
||||
interface SpaceAssignmentPayload {
|
||||
export interface SpaceAssignmentPayload {
|
||||
userId: string;
|
||||
workspaceId: string;
|
||||
mode: "new_space" | "episode";
|
||||
|
||||
@ -1,22 +1,16 @@
|
||||
FROM neo4j:5
|
||||
FROM neo4j:5.26.0
|
||||
|
||||
# Set environment variables for plugin versions
|
||||
# GDS 2.13 is compatible with Neo4j 5.26
|
||||
# APOC 5.26.14 is the latest for Neo4j 5.x
|
||||
ENV GDS_VERSION=2.13.0
|
||||
ENV APOC_VERSION=5.26.0
|
||||
|
||||
# Install GDS and APOC plugins
|
||||
# Manual installation of plugins with correct download URLs
|
||||
# GDS 2.13.2 is compatible with Neo4j 5.26
|
||||
# APOC 5.26.0 matches Neo4j 5.26
|
||||
RUN apt-get update && apt-get install -y curl && \
|
||||
curl -L https://github.com/neo4j/graph-data-science/releases/download/${GDS_VERSION}/neo4j-graph-data-science-${GDS_VERSION}.jar \
|
||||
-o /var/lib/neo4j/plugins/neo4j-graph-data-science-${GDS_VERSION}.jar && \
|
||||
curl -L https://github.com/neo4j/apoc/releases/download/${APOC_VERSION}/apoc-${APOC_VERSION}-core.jar \
|
||||
-o /var/lib/neo4j/plugins/apoc-${APOC_VERSION}-core.jar && \
|
||||
curl -L https://github.com/neo4j/graph-data-science/releases/download/2.13.2/neo4j-graph-data-science-2.13.2.jar \
|
||||
-o /var/lib/neo4j/plugins/neo4j-graph-data-science.jar && \
|
||||
curl -L https://github.com/neo4j/apoc/releases/download/5.26.0/apoc-5.26.0-core.jar \
|
||||
-o /var/lib/neo4j/plugins/apoc-core.jar && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R neo4j:neo4j /var/lib/neo4j/plugins
|
||||
rm -rf /var/lib/apt/lists/* && \
|
||||
chown -R neo4j:neo4j /var/lib/neo4j/plugins
|
||||
|
||||
# Default configuration for GDS and APOC
|
||||
ENV NEO4J_dbms_security_procedures_unrestricted=gds.*,apoc.*
|
||||
|
||||
@ -42,6 +42,9 @@ services:
|
||||
- FROM_EMAIL=${FROM_EMAIL}
|
||||
- RESEND_API_KEY=${RESEND_API_KEY}
|
||||
- COHERE_API_KEY=${COHERE_API_KEY}
|
||||
- QUEUE_PROVIDER=${QUEUE_PROVIDER}
|
||||
- TELEMETRY_ENABLED=${TELEMETRY_ENABLED}
|
||||
- TELEMETRY_ANONYMOUS=${TELEMETRY_ANONYMOUS}
|
||||
ports:
|
||||
- "3033:3000"
|
||||
depends_on:
|
||||
@ -84,7 +87,7 @@ services:
|
||||
|
||||
neo4j:
|
||||
container_name: core-neo4j
|
||||
image: neo4j:5
|
||||
image: redplanethq/neo4j:0.1.0
|
||||
environment:
|
||||
- NEO4J_AUTH=${NEO4J_AUTH}
|
||||
- NEO4J_dbms_security_procedures_unrestricted=gds.*,apoc.*
|
||||
@ -94,7 +97,6 @@ services:
|
||||
- NEO4J_apoc_import_file_use_neo4j_config=true
|
||||
- NEO4J_server_memory_heap_initial__size=2G
|
||||
- NEO4J_server_memory_heap_max__size=4G
|
||||
- NEO4JLABS_PLUGINS=apoc,graph-data-science
|
||||
ports:
|
||||
- "7474:7474"
|
||||
- "7687:7687"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user