Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add web page as source of prompt #26

Merged
merged 1 commit into from
Oct 18, 2024
Merged
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
149 changes: 41 additions & 108 deletions app/(playground)/p/[agentId]/beta-proto/artifact/schema.ts
Original file line number Diff line number Diff line change
@@ -1,117 +1,50 @@
import { jsonSchema } from "ai";
import type { GeneratedObject } from "./types";

export const schema = jsonSchema<GeneratedObject>(
{
type: "object",
properties: {
thinking: {
type: "string",
description:
"How you think about the content of the artefact (purpose, structure, essentials) and how you intend to output it",
},
artifact: {
type: "object",
properties: {
title: { type: "string", description: "The title of the artefact" },
content: {
type: "string",
description: "The content of the artefact formatted markdown",
},
completed: {
type: "boolean",
description: "Whether the artefact is completed",
export const schema = jsonSchema<GeneratedObject>({
type: "object",
properties: {
thinking: {
type: "string",
description:
"How you think about the content of the artefact (purpose, structure, essentials) and how you intend to output it",
},
artifact: {
type: "object",
properties: {
title: { type: "string", description: "The title of the artefact" },
content: {
type: "string",
description: `The content of the artefact formatted markdown.`,
},
citations: {
type: "array",
items: {
type: "object",
properties: {
title: {
type: "string",
description: "The title of the citation page",
},
url: {
type: "string",
description: "The URL of the citation page",
},
},
},
},
required: ["title", "content", "completed"],
},
description: {
type: "string",
description:
"Explanation of the Artifact and what the intention was in creating this Artifact. Add any suggestions for making it even better.",
completed: {
type: "boolean",
description: "Whether the artefact is completed",
},
},
required: ["title", "citations", "content", "completed"],
},
required: ["thinking", "artifact", "description"],
},
{
validate: (value) => {
if (!isObject(value)) {
return { success: false, error: new Error("value must be an object") };
}

const { thinking, artifact, description, completed } = value;

if (!isString(thinking)) {
return {
success: false,
error: new Error("thinking must be a string"),
};
}

if (!isObject(artifact)) {
return {
success: false,
error: new Error("artifact must be an object"),
};
}

const { title, content } = artifact;

if (!isString(title)) {
return {
success: false,
error: new Error("artifact.title must be a string"),
};
}

if (!isString(content)) {
return {
success: false,
error: new Error("artifact.content must be a string"),
};
}

if (!isString(content)) {
return {
success: false,
error: new Error("artifact.content must be a string"),
};
}

if (!isBoolean(completed)) {
return {
success: false,
error: new Error("artifact.completed must be a boolean"),
};
}

if (description === undefined) {
return {
success: false,
error: new Error("description must be a string if provided"),
};
}
if (!isString(description)) {
return {
success: false,
error: new Error("description must be a string if provided"),
};
}
if (!isBoolean(completed)) {
return {
success: false,
error: new Error("artifact.completed must be a boolean"),
};
}

return {
success: true,
value: {
thinking,
artifact: { title, content, completed },
description,
},
};
description: {
type: "string",
description:
"Explanation of the Artifact and what the intention was in creating this Artifact. Add any suggestions for making it even better.",
},
},
);
required: ["thinking", "artifact", "description"],
});
11 changes: 10 additions & 1 deletion app/(playground)/p/[agentId]/beta-proto/artifact/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,18 @@ export type ArtifactReference = {
object: "artifact.reference";
};

interface Citation {
title: string;
url: string;
}
export type GeneratedObject = {
thinking: string;
artifact: { title: string; content: string; completed: boolean };
artifact: {
title: string;
content: string;
citations: Citation[];
completed: boolean;
};
description: string;
};
export type PartialGeneratedObject = Partial<GeneratedObject>;
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,22 @@ import type { GiselleNode } from "../../types";
import { Block } from "./block";
import { MarkdownRender } from "./markdown-render";

interface Citation {
title: string;
url: string;
}
type ArtifactBlockProps = {
title?: string;
content?: string;
citations?: Citation[];
completed?: boolean;
node: Pick<GiselleNode, "archetype" | "name">;
};
export function ArtifactBlock(props: ArtifactBlockProps) {
const title = props.title ?? "Generating...";
const content = props.content ?? "";
const completed = props.completed ?? false;
const citations = props.citations ?? [];
return (
<Dialog>
<DialogTrigger>
Expand Down Expand Up @@ -48,7 +54,15 @@ export function ArtifactBlock(props: ArtifactBlockProps) {
<div className="border-t border-black-40" />
<div className="overflow-x-hidden overflow-y-auto flex-1">
<div className="px-[32px] py-[16px] font-rosart text-[18px] text-black-30">
<MarkdownRender markdownLike={content} />
<MarkdownRender
markdownLike={`
${content}

${citations.length > 0 ? "## Citations" : ""}

${citations.map((citation) => `[${citation.title}](${citation.url})`).join("\n")}
`}
/>
</div>
</div>
<div className="px-[32px] flex items-center py-[12px] justify-between">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type {
TextContent,
TextContentReference,
} from "../../../text-content/types";
import type { WebSearch } from "../../../web-search/types";
import {
type GiselleNode,
type GiselleNodeId,
Expand Down Expand Up @@ -67,7 +68,7 @@ function setTextToPropertyAndOutput(
};
}

type Source = ArtifactReference | TextContent | GiselleFile;
type Source = ArtifactReference | TextContent | GiselleFile | WebSearch;

type PromptPropertyPanelProps = {
node: GiselleNode;
Expand Down Expand Up @@ -145,21 +146,30 @@ export const PromptPropertyPanel: FC<PromptPropertyPanelProps> = ({ node }) => {
);
}, [dispatch, outgoingConnections]);

const availableArtifacts = useMemo<Artifact[]>(
() =>
state.graph.artifacts.filter(
const availableArtifactsOrWebSearches = useMemo<(Artifact | WebSearch)[]>(
() => [
...state.graph.artifacts.filter(
(artifact) =>
!outgoingConnections.some(
({ target }) => target === artifact.generatorNode.id,
),
),
[outgoingConnections, state.graph.artifacts],
...state.graph.webSearches.filter(
(webSearch) =>
!outgoingConnections.some(
({ target }) => target === webSearch.generatorNode.id,
),
),
],
[outgoingConnections, state.graph.artifacts, state.graph.webSearches],
);
const sources = useMemo<(Artifact | TextContent | GiselleFile)[]>(
const sources = useMemo<(Artifact | TextContent | GiselleFile | WebSearch)[]>(
() =>
(node.properties.sources as Source[])
?.map((source) =>
source.object === "textContent" || source.object === "file"
source.object === "textContent" ||
source.object === "file" ||
source.object === "webSearch"
? source
: state.graph.artifacts.find(
(artifact) => artifact.id === source.id,
Expand Down Expand Up @@ -199,6 +209,31 @@ export const PromptPropertyPanel: FC<PromptPropertyPanelProps> = ({ node }) => {
},
[dispatch, node.id, sources],
);
const handleWebSearchClick = useCallback(
(webSearch: WebSearch) => () => {
const webSearchIds = sources.map(({ id }) => id);
if (webSearchIds.includes(webSearch.id)) {
dispatch(
removeSourceFromPromptNode({
promptNode: {
id: node.id,
},
source: webSearch,
}),
);
} else {
dispatch(
addSourceToPromptNode({
promptNode: {
id: node.id,
},
source: webSearch,
}),
);
}
},
[dispatch, node.id, sources],
);
const removeTextContent = useCallback(
(textContent: Pick<TextContentReference, "id">) => () => {
dispatch(
Expand Down Expand Up @@ -323,26 +358,54 @@ export const PromptPropertyPanel: FC<PromptPropertyPanelProps> = ({ node }) => {
>
<div className="px-[8px]">
<div>
{availableArtifacts.map((artifact) => (
<button
type="button"
className="flex justify-between items-center py-[4px] w-full"
key={artifact.id}
onClick={handleArtifactClick(artifact)}
>
<p className="line-clamp-1 text-left">
{artifact.title}
</p>
{sources.some(
(source) => source.id === artifact.id,
) && (
<CheckIcon
size={16}
className="stroke-white flex-shrink-0"
/>
)}
</button>
))}
{availableArtifactsOrWebSearches.map(
(artifactOrWebSearch) =>
artifactOrWebSearch.object === "artifact" ? (
<button
type="button"
className="flex justify-between items-center py-[4px] w-full"
key={artifactOrWebSearch.id}
onClick={handleArtifactClick(
artifactOrWebSearch,
)}
>
<p className="line-clamp-1 text-left">
{artifactOrWebSearch.title}
</p>
{sources.some(
(source) =>
source.id === artifactOrWebSearch.id,
) && (
<CheckIcon
size={16}
className="stroke-white flex-shrink-0"
/>
)}
</button>
) : (
<button
type="button"
className="flex justify-between items-center py-[4px] w-full"
key={artifactOrWebSearch.id}
onClick={handleWebSearchClick(
artifactOrWebSearch,
)}
>
<p className="line-clamp-1 text-left">
{artifactOrWebSearch.name}
</p>
{sources.some(
(source) =>
source.id === artifactOrWebSearch.id,
) && (
<CheckIcon
size={16}
className="stroke-white flex-shrink-0"
/>
)}
</button>
),
)}
</div>
</div>
</Popover.Content>
Expand Down Expand Up @@ -376,6 +439,14 @@ export const PromptPropertyPanel: FC<PromptPropertyPanelProps> = ({ node }) => {
<DocumentIcon className="w-[18px] h-[18px] fill-black-30 flex-shrink-0" />
}
/>
) : source.object === "webSearch" ? (
<Block
key={source.id}
title={source.name}
icon={
<TextsIcon className="w-[18px] h-[18px] fill-black-30 flex-shrink-0" />
}
/>
) : (
<Block
key={source.id}
Expand Down
Loading