Skip to content

Commit

Permalink
add web page as source of prompt
Browse files Browse the repository at this point in the history
  • Loading branch information
toyamarinyon committed Oct 18, 2024
1 parent 6e2876a commit ace3205
Show file tree
Hide file tree
Showing 9 changed files with 313 additions and 149 deletions.
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

0 comments on commit ace3205

Please sign in to comment.