Skip to content

Commit 63b23f9

Browse files
enekesabeljpr5
authored andcommitted
feat(vue): implement core hooks and composables
Vue 3 composition API hooks matching React hook parity: agents, attachments, suggestions, frontend tools, HITL, interrupts, threads, keyboard/katex utilities, and pin-to-send.
1 parent 92c0f0e commit 63b23f9

18 files changed

Lines changed: 2343 additions & 0 deletions

packages/vue/src/hooks/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
export { useCopilotAction } from "./use-copilot-action";
2+
export type {
3+
FrontendAction,
4+
CatchAllFrontendAction,
5+
} from "./use-copilot-action";
6+
export { useFrontendTool } from "./use-frontend-tool";
7+
export type { UseFrontendToolArgs } from "./use-frontend-tool";
8+
export { useCopilotReadable } from "./use-copilot-readable";
9+
export type { UseCopilotReadableOptions } from "./use-copilot-readable";
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/**
2+
* V1 compatibility wrapper for useFrontendTool.
3+
*
4+
* Accepts the legacy Parameter[] format and converts to Zod via getZodParameters,
5+
* then delegates to the v2 composable.
6+
*/
7+
import type { WatchSource } from "vue";
8+
import {
9+
type Parameter,
10+
type MappedParameterTypes,
11+
getZodParameters,
12+
parseJson,
13+
} from "@copilotkit/shared";
14+
import { useFrontendTool as useFrontendToolV2 } from "../v2/hooks/use-frontend-tool";
15+
import type { VueFrontendTool } from "../v2/types";
16+
17+
export interface UseFrontendToolArgs<T extends Parameter[] | [] = []> {
18+
name: string;
19+
description?: string;
20+
parameters?: T;
21+
handler?: (args: MappedParameterTypes<T>) => unknown | Promise<unknown>;
22+
followUp?: boolean;
23+
available?: "disabled" | "enabled";
24+
render?: VueFrontendTool<MappedParameterTypes<T>>["render"];
25+
agentId?: string;
26+
}
27+
28+
export function useFrontendTool<const T extends Parameter[] = []>(
29+
tool: UseFrontendToolArgs<T>,
30+
deps?: WatchSource<unknown>[],
31+
) {
32+
const {
33+
name,
34+
description,
35+
parameters,
36+
handler,
37+
followUp,
38+
available,
39+
render,
40+
agentId,
41+
} = tool;
42+
const zodParameters = getZodParameters(parameters);
43+
44+
// Wrap the v1 handler (single-arg) to match v2's (args, context) => Promise<unknown> signature
45+
const normalizedHandler = handler
46+
? (args: MappedParameterTypes<T>) => Promise.resolve(handler(args))
47+
: undefined;
48+
49+
// Wrap render to parse JSON-string results before passing them to the
50+
// user's render function — matches the v1 React behavior. If render is a
51+
// Component rather than a function, leave it unchanged.
52+
const normalizedRender =
53+
typeof render === "function"
54+
? ((props: { result?: unknown }) => {
55+
const renderProps =
56+
typeof props.result === "string"
57+
? { ...props, result: parseJson(props.result, props.result) }
58+
: props;
59+
return (render as (p: unknown) => unknown)(renderProps);
60+
})
61+
: render;
62+
63+
useFrontendToolV2<MappedParameterTypes<T>>(
64+
{
65+
name,
66+
description,
67+
parameters: zodParameters,
68+
handler: normalizedHandler,
69+
followUp,
70+
render: normalizedRender,
71+
available: available === undefined ? undefined : available !== "disabled",
72+
agentId,
73+
},
74+
deps,
75+
);
76+
}

packages/vue/src/v2/hooks/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
export { useAgent, UseAgentUpdate } from "./use-agent";
2+
export { useAgentContext } from "./use-agent-context";
3+
export type { AgentContextInput, JsonSerializable } from "./use-agent-context";
4+
export { useFrontendTool } from "./use-frontend-tool";
5+
export { useComponent } from "./use-component";
6+
export { useRenderTool } from "./use-render-tool";
7+
export { useDefaultRenderTool } from "./use-default-render-tool";
8+
export { useHumanInTheLoop } from "./use-human-in-the-loop";
9+
export { useSuggestions } from "./use-suggestions";
10+
export type {
11+
UseSuggestionsOptions,
12+
UseSuggestionsResult,
13+
} from "./use-suggestions";
14+
export { useConfigureSuggestions } from "./use-configure-suggestions";
15+
export { useInterrupt } from "./use-interrupt";
16+
export type { UseInterruptConfig, UseInterruptResult } from "./use-interrupt";
17+
export { useThreads } from "./use-threads";
18+
export type { Thread, UseThreadsInput, UseThreadsResult } from "./use-threads";
19+
export { useAttachments } from "./use-attachments";
20+
export type {
21+
UseAttachmentsProps,
22+
UseAttachmentsReturn,
23+
} from "./use-attachments";
24+
export { useKeyboardHeight } from "./use-keyboard-height";
25+
export type { KeyboardState } from "./use-keyboard-height";
26+
export { useKatexStyles } from "./use-katex-styles";
27+
export { useCapabilities } from "./use-capabilities";
28+
export { useRenderCustomMessages } from "./use-render-custom-messages";
29+
export { useRenderActivityMessage } from "./use-render-activity-message";
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { computed, toValue, watch } from "vue";
2+
import type { MaybeRefOrGetter } from "vue";
3+
import { useCopilotKit } from "../providers/useCopilotKit";
4+
5+
export type JsonSerializable =
6+
| string
7+
| number
8+
| boolean
9+
| null
10+
| JsonSerializable[]
11+
| { [key: string]: JsonSerializable };
12+
13+
export interface AgentContextInput {
14+
description: MaybeRefOrGetter<string>;
15+
value: MaybeRefOrGetter<JsonSerializable>;
16+
}
17+
18+
/**
19+
* Registers reactive contextual data that is sent with agent runs.
20+
*
21+
* The context entry is added when the composable is active and removed
22+
* automatically on scope cleanup.
23+
*
24+
* @example
25+
* ```ts
26+
* useAgentContext({
27+
* description: "Current workspace",
28+
* value: "copilotkit-vue",
29+
* });
30+
* ```
31+
*/
32+
export function useAgentContext(context: AgentContextInput): void {
33+
const { copilotkit } = useCopilotKit();
34+
const resolvedDescription = computed(() => toValue(context.description));
35+
const resolvedValue = computed(() => toValue(context.value));
36+
37+
const stringValue = computed(() =>
38+
typeof resolvedValue.value === "string"
39+
? resolvedValue.value
40+
: JSON.stringify(resolvedValue.value),
41+
);
42+
43+
watch(
44+
[() => copilotkit.value, resolvedDescription, stringValue],
45+
(_newValues, _old, onCleanup) => {
46+
const core = copilotkit.value;
47+
const id = core.addContext({
48+
description: resolvedDescription.value,
49+
value: stringValue.value,
50+
});
51+
onCleanup(() => core.removeContext(id));
52+
},
53+
{ immediate: true },
54+
);
55+
}

0 commit comments

Comments
 (0)