合并 agent-mvp 到 master #1
@@ -3,14 +3,50 @@
|
|||||||
import { useCallback, useEffect, useRef, useState } from "react";
|
import { useCallback, useEffect, useRef, useState } from "react";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
|
|
||||||
import { abortAgentChat, forkAgentChat, rejectAgentQuestion, replyAgentCredentialRefresh, replyAgentPermission, replyAgentQuestion, resumeAgentChatStream, streamAgentChat } from "@/lib/chatStream";
|
import {
|
||||||
|
abortAgentChat,
|
||||||
|
forkAgentChat,
|
||||||
|
rejectAgentQuestion,
|
||||||
|
replyAgentCredentialRefresh,
|
||||||
|
replyAgentPermission,
|
||||||
|
replyAgentQuestion,
|
||||||
|
resumeAgentChatStream,
|
||||||
|
streamAgentChat,
|
||||||
|
} from "@/lib/chatStream";
|
||||||
import type { PermissionReply, StreamEvent } from "@/lib/chatStream";
|
import type { PermissionReply, StreamEvent } from "@/lib/chatStream";
|
||||||
import { useAuthStore } from "@/store/authStore";
|
import { useAuthStore } from "@/store/authStore";
|
||||||
import type { AgentArtifact, ChatSessionSummary, Message } from "../GlobalChatbox.types";
|
import type {
|
||||||
|
AgentArtifact,
|
||||||
|
ChatSessionSummary,
|
||||||
|
Message,
|
||||||
|
} from "../GlobalChatbox.types";
|
||||||
import { cloneMessages } from "../globalChatboxUtils";
|
import { cloneMessages } from "../globalChatboxUtils";
|
||||||
import { createEmptyChatState, deleteChatSession, listChatSessions, loadChatSessionById, updateChatSessionTitle } from "../chatStorage";
|
import {
|
||||||
import { applyQuestionResponse, cancelRunningTodos, completeRunningProgress, createAssistantMessage, createTodoUpdateFromEvent, createUserMessage, dedupeQuestionsAcrossMessages, finalizeAssistantMessageAfterAbort, normalizeSessionTodos, toPermissionStatus, upsertPermission, upsertProgress, upsertQuestionAcrossMessages } from "./agentChatSessionState";
|
createEmptyChatState,
|
||||||
import type { PromptRunOptions, UseAgentChatSessionOptions } from "./useAgentChatSession.types";
|
deleteChatSession,
|
||||||
|
listChatSessions,
|
||||||
|
loadChatSessionById,
|
||||||
|
updateChatSessionTitle,
|
||||||
|
} from "../chatStorage";
|
||||||
|
import {
|
||||||
|
applyQuestionResponse,
|
||||||
|
cancelRunningTodos,
|
||||||
|
completeRunningProgress,
|
||||||
|
createAssistantMessage,
|
||||||
|
createTodoUpdateFromEvent,
|
||||||
|
createUserMessage,
|
||||||
|
dedupeQuestionsAcrossMessages,
|
||||||
|
finalizeAssistantMessageAfterAbort,
|
||||||
|
normalizeSessionTodos,
|
||||||
|
toPermissionStatus,
|
||||||
|
upsertPermission,
|
||||||
|
upsertProgress,
|
||||||
|
upsertQuestionAcrossMessages,
|
||||||
|
} from "./agentChatSessionState";
|
||||||
|
import type {
|
||||||
|
PromptRunOptions,
|
||||||
|
UseAgentChatSessionOptions,
|
||||||
|
} from "./useAgentChatSession.types";
|
||||||
|
|
||||||
const TOKEN_PLAYBACK_INTERVAL_MS = 16;
|
const TOKEN_PLAYBACK_INTERVAL_MS = 16;
|
||||||
const TOKEN_PLAYBACK_BASE_CHARS = 28;
|
const TOKEN_PLAYBACK_BASE_CHARS = 28;
|
||||||
|
|||||||
+33
-14
@@ -1,6 +1,11 @@
|
|||||||
import { apiFetch } from "@/lib/apiFetch";
|
import { apiFetch } from "@/lib/apiFetch";
|
||||||
import { config } from "@config/config";
|
import { config } from "@config/config";
|
||||||
|
|
||||||
|
const AGENT_SESSIONS_URL = `${config.AGENT_URL}/api/v1/agent/sessions`;
|
||||||
|
|
||||||
|
const getAgentSessionUrl = (sessionId: string, suffix = "") =>
|
||||||
|
`${AGENT_SESSIONS_URL}/${encodeURIComponent(sessionId)}${suffix}`;
|
||||||
|
|
||||||
export type AgentModel = string;
|
export type AgentModel = string;
|
||||||
|
|
||||||
export type PermissionReply = "once" | "always" | "reject";
|
export type PermissionReply = "once" | "always" | "reject";
|
||||||
@@ -509,7 +514,7 @@ const readStreamEvents = async (
|
|||||||
const ensureAgentSession = async (sessionId?: string) => {
|
const ensureAgentSession = async (sessionId?: string) => {
|
||||||
if (sessionId) return sessionId;
|
if (sessionId) return sessionId;
|
||||||
|
|
||||||
const response = await apiFetch(`${config.AGENT_URL}/api/v1/agent/sessions`, {
|
const response = await apiFetch(AGENT_SESSIONS_URL, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -519,7 +524,10 @@ const ensureAgentSession = async (sessionId?: string) => {
|
|||||||
skipAuthRedirect: true,
|
skipAuthRedirect: true,
|
||||||
});
|
});
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error((await response.text()) || `session creation failed: ${response.status}`);
|
throw new Error(
|
||||||
|
(await response.text()) ||
|
||||||
|
`session creation failed: ${response.status}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
const payload = (await response.json()) as { session_id?: string };
|
const payload = (await response.json()) as { session_id?: string };
|
||||||
if (!payload.session_id) {
|
if (!payload.session_id) {
|
||||||
@@ -540,7 +548,7 @@ export const streamAgentChat = async ({
|
|||||||
try {
|
try {
|
||||||
const effectiveSessionId = await ensureAgentSession(sessionId);
|
const effectiveSessionId = await ensureAgentSession(sessionId);
|
||||||
response = await apiFetch(
|
response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(effectiveSessionId)}/runs`,
|
getAgentSessionUrl(effectiveSessionId, "/runs"),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
signal,
|
signal,
|
||||||
@@ -597,7 +605,7 @@ export const resumeAgentChatStream = async ({
|
|||||||
let response: Response;
|
let response: Response;
|
||||||
try {
|
try {
|
||||||
response = await apiFetch(
|
response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/runs/current/events`,
|
getAgentSessionUrl(sessionId, "/runs/current/events"),
|
||||||
{
|
{
|
||||||
method: "GET",
|
method: "GET",
|
||||||
signal,
|
signal,
|
||||||
@@ -638,11 +646,14 @@ export const abortAgentChat = async (sessionId?: string) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await apiFetch(`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/runs/current`, {
|
const response = await apiFetch(
|
||||||
|
getAgentSessionUrl(sessionId, "/runs/current"),
|
||||||
|
{
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
projectHeaderMode: "include",
|
projectHeaderMode: "include",
|
||||||
skipAuthRedirect: true,
|
skipAuthRedirect: true,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const detail = await response.text();
|
const detail = await response.text();
|
||||||
@@ -656,7 +667,7 @@ export const replyAgentPermission = async (
|
|||||||
reply: PermissionReply,
|
reply: PermissionReply,
|
||||||
) => {
|
) => {
|
||||||
const response = await apiFetch(
|
const response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/permission-responses`,
|
getAgentSessionUrl(sessionId, "/permission-responses"),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -682,7 +693,7 @@ export const replyAgentCredentialRefresh = async (
|
|||||||
requestId: string,
|
requestId: string,
|
||||||
) => {
|
) => {
|
||||||
const response = await apiFetch(
|
const response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/credential-refreshes`,
|
getAgentSessionUrl(sessionId, "/credential-refreshes"),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: { "Content-Type": "application/json" },
|
headers: { "Content-Type": "application/json" },
|
||||||
@@ -693,7 +704,9 @@ export const replyAgentCredentialRefresh = async (
|
|||||||
);
|
);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const detail = await response.text();
|
const detail = await response.text();
|
||||||
throw new Error(detail || `credential refresh reply failed: ${response.status}`);
|
throw new Error(
|
||||||
|
detail || `credential refresh reply failed: ${response.status}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -703,7 +716,7 @@ export const replyAgentQuestion = async (
|
|||||||
answers: string[][],
|
answers: string[][],
|
||||||
) => {
|
) => {
|
||||||
const response = await apiFetch(
|
const response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/question-responses`,
|
getAgentSessionUrl(sessionId, "/question-responses"),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -730,7 +743,7 @@ export const rejectAgentQuestion = async (
|
|||||||
requestId: string,
|
requestId: string,
|
||||||
) => {
|
) => {
|
||||||
const response = await apiFetch(
|
const response = await apiFetch(
|
||||||
`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId)}/question-responses`,
|
getAgentSessionUrl(sessionId, "/question-responses"),
|
||||||
{
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
@@ -751,8 +764,13 @@ export const rejectAgentQuestion = async (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const forkAgentChat = async (sessionId: string | undefined, keepMessageCount: number) => {
|
export const forkAgentChat = async (
|
||||||
const response = await apiFetch(`${config.AGENT_URL}/api/v1/agent/sessions/${encodeURIComponent(sessionId ?? "")}/forks`, {
|
sessionId: string | undefined,
|
||||||
|
keepMessageCount: number,
|
||||||
|
) => {
|
||||||
|
const response = await apiFetch(
|
||||||
|
getAgentSessionUrl(sessionId ?? "", "/forks"),
|
||||||
|
{
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
@@ -762,7 +780,8 @@ export const forkAgentChat = async (sessionId: string | undefined, keepMessageCo
|
|||||||
}),
|
}),
|
||||||
projectHeaderMode: "include",
|
projectHeaderMode: "include",
|
||||||
skipAuthRedirect: true,
|
skipAuthRedirect: true,
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
const detail = await response.text();
|
const detail = await response.text();
|
||||||
|
|||||||
Reference in New Issue
Block a user