Files
Tyler Slaton 96885b5959 refactor: consolidate V1/V2 packages into flat @copilotkit/* structure
Flatten all packages from packages/v1/* and packages/v2/* into packages/* —
every package now lives directly under the @copilotkit/ scope with no v1/v2
subdirectories.

- Move all v1 packages (react-core, react-ui, runtime, shared, etc.) from
  packages/v1/* to packages/*
- Absorb v2 react code into packages/react-core/src/v2/ (exported via /v2 subpath)
- Absorb v2 agent code into packages/runtime/src/agent/ (exported via /v2 subpath)
- Move v2 packages (core, angular, demo-agents, etc.) to packages/*
- Replace all @copilotkitnext/* imports with @copilotkit/* equivalents
- Keep @copilotkitnext/angular as the sole exception (angular remains on next)
- Update CI workflows, renovate config, release scripts for flat structure
- No public API surface changes — all exports fields are preserved

Co-authored-by: Alem Tuzlak <t.zlak@hotmail.com>
Signed-off-by: Tyler Slaton <tyler@copilotkit.ai>
2026-03-28 16:45:10 -07:00

138 lines
3.9 KiB
TypeScript

import {
AbstractAgent,
RunAgentInput,
EventType,
BaseEvent,
ToolCallResultEvent,
} from "@ag-ui/client";
import { Observable } from "rxjs";
export class SlowToolCallStreamingAgent extends AbstractAgent {
private delay = 200; // 0.2 seconds delay between chunks
constructor(delayMs: number = 200) {
super();
this.delay = delayMs;
}
clone(): SlowToolCallStreamingAgent {
return new SlowToolCallStreamingAgent(this.delay);
}
private sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}
run(input: RunAgentInput): Observable<BaseEvent> {
return new Observable<BaseEvent>((observer) => {
let cancelled = false;
const runAsync = async () => {
await this.sleep(1000);
try {
const messageId = Date.now().toString();
const toolCallId = `call_${Date.now()}`;
// Start the run
observer.next({
type: EventType.RUN_STARTED,
threadId: input.threadId,
runId: input.runId,
} as BaseEvent);
// Stream the initial text message
const textMessage =
"I'll check the weather for you. Let me fetch that information ok?.";
const chunks = textMessage.split(" ");
for (let i = 0; i < chunks.length; i++) {
if (cancelled) return;
observer.next({
type: EventType.TEXT_MESSAGE_CHUNK,
messageId,
delta: (i > 0 ? " " : "") + chunks[i],
} as BaseEvent);
await this.sleep(this.delay);
}
// Stream the tool call
const toolCallArgs = JSON.stringify({
location: "San Francisco",
unit: "celsius",
});
const toolCallChunks: string[] = [];
for (let i = 0; i < toolCallArgs.length; i += 5) {
toolCallChunks.push(toolCallArgs.slice(i, i + 5));
}
for (let i = 0; i < toolCallChunks.length; i++) {
if (cancelled) return;
if (i === 0) {
// First chunk includes tool name
observer.next({
type: EventType.TOOL_CALL_CHUNK,
toolCallId,
toolCallName: "getWeather",
parentMessageId: messageId,
delta: toolCallChunks[0],
} as BaseEvent);
} else {
// Subsequent chunks only include arguments
observer.next({
type: EventType.TOOL_CALL_CHUNK,
toolCallId,
parentMessageId: messageId,
delta: toolCallChunks[i],
} as BaseEvent);
}
await this.sleep(this.delay);
}
// Send tool result
if (cancelled) return;
const toolResultMessageId = `${Date.now()}_tool_result`;
observer.next({
type: EventType.TOOL_CALL_RESULT,
toolCallId,
content: JSON.stringify({
temperature: 18,
unit: "celsius",
condition: "partly cloudy",
humidity: 65,
windSpeed: 12,
}),
messageId: toolResultMessageId,
} as ToolCallResultEvent);
// Complete the run
if (cancelled) return;
observer.next({
type: EventType.RUN_FINISHED,
threadId: input.threadId,
runId: input.runId,
} as BaseEvent);
observer.complete();
} catch (error) {
if (!cancelled) {
observer.next({
type: EventType.RUN_ERROR,
message:
error instanceof Error
? error.message
: "Unknown error occurred",
} as BaseEvent);
observer.error(error);
}
}
};
runAsync();
// Cleanup function
return () => {
cancelled = true;
};
});
}
}