[PR #686] [MERGED] feat: support human in the loop for TS #686

Closed
opened 2026-02-15 20:15:51 -05:00 by yindo · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/run-llama/create-llama/pull/686
Author: @thucpn
Created: 6/9/2025
Status: Merged
Merged: 6/12/2025
Merged by: @thucpn

Base: mainHead: tp/hitl-for-ts


📝 Commits (10+)

  • e4c07f9 feat: support human in the loop for TS
  • eba44a3 add example for custom workflow
  • 7875178 fix: need to request humanResponseEvent to save missing step to snapshot
  • ac5a1ef refactor: human response data should be any
  • 832f5b6 refactor runWorkflow function to support resume stream
  • 23fdd51 refactor: hitl
  • 7b21682 fix: workflow
  • ddccbcf add summary event
  • 45af254 send tool event
  • be894df use requestId from Vercel

📊 Changes

41 files changed (+1653 additions, -91 deletions)

View changed files

.changeset/eight-moons-perform.md (+6 -0)
📝 packages/create-llama/e2e/python/resolve_dependencies.spec.ts (+1 -0)
📝 packages/create-llama/e2e/shared/llamaindexserver_template.spec.ts (+1 -0)
📝 packages/create-llama/e2e/typescript/resolve_dependencies.spec.ts (+3 -1)
📝 packages/create-llama/helpers/constant.ts (+9 -0)
📝 packages/create-llama/helpers/index.ts (+3 -1)
📝 packages/create-llama/helpers/types.ts (+2 -1)
📝 packages/create-llama/helpers/typescript.ts (+2 -1)
📝 packages/create-llama/questions/simple.ts (+17 -2)
packages/create-llama/templates/components/ui/use-cases/hitl/cli_human_input.tsx (+95 -0)
packages/create-llama/templates/components/use-cases/python/hitl/README-template.md (+109 -0)
packages/create-llama/templates/components/use-cases/python/hitl/events.py (+34 -0)
packages/create-llama/templates/components/use-cases/python/hitl/workflow.py (+87 -0)
packages/create-llama/templates/components/use-cases/typescript/hitl/README-template.md (+106 -0)
packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/events.ts (+12 -0)
packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/tools.ts (+20 -0)
packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/workflow.ts (+101 -0)
📝 packages/create-llama/templates/types/llamaindexserver/nextjs/package.json (+2 -2)
📝 packages/server/README.md (+1 -0)
packages/server/examples/hitl/README.md (+172 -0)

...and 21 more files

📄 Description

Pattern:

import { createWorkflow, workflowEvent } from "@llama-flow/core";
import { request, withSnapshot } from "@llama-flow/core/middleware/snapshot";
import fs from "fs";

///////////// EVENTS /////////////
const startEvent = workflowEvent<string>({
	debugLabel: "Start event",
});
const humamInputEvent = workflowEvent<string>({
	debugLabel: "Human input event",
});
const humanResponseEvent = workflowEvent<string>({
	debugLabel: "Human response event",
});
const stopEvent = workflowEvent<string>({
	debugLabel: "Stop event",
});

///////////// CLIENT CODE: WORKFLOW DEFINITION /////////////
const workflowFactory = () => {
	const workflow = withSnapshot(createWorkflow());

	workflow.handle([startEvent], ({ data: startInput }) => {
		console.log("Start event---");

		const shouldRequestHuman = startInput.length < 3; // condition to request human

		if (shouldRequestHuman) {
			// request human input with a reason
			return humamInputEvent.with("input length < 3");
		}

		// if no need to request human, stop the workflow
		return stopEvent.with("Stop without request human");
	});

	workflow.handle([humanResponseEvent], ({ data: userInput }) => {
		// userInput is the input from human
		// we can trigger LLM with user input to get final result
		const sampleFinalResult = "Sample final result for human input: " + userInput;
		return stopEvent.with(sampleFinalResult);
	});

	return workflow;
};

///////////// SERVER CODE: RUN & RESUME WORKFLOW /////////////
const runWorkflow = async () => {
	const workflow = workflowFactory();
	const { sendEvent, stream, snapshot, onRequest } = workflow.createContext();

	// try send a start event with empty input to trigger human input
	sendEvent(startEvent.with(""));

	// consume stream
	for await (const event of stream) {
		if (humamInputEvent.include(event)) {
			console.log("Need to request human input with reason: ", event.data);

			// send a request event
			sendEvent(request(humanResponseEvent));

			// save snapshot
			const [_, snapshotData] = await snapshot();
			console.log("Snapshot data: ", snapshotData);
			fs.writeFileSync("snapshot.json", JSON.stringify(snapshotData, null, 2));

			// stop the workflow
			break;
		}

		console.log(event.data);
	}
};

const resumeWorkflow = async () => {
	const workflow = workflowFactory();
	const snapshotData = JSON.parse(fs.readFileSync("snapshot.json", "utf8"));
	const { stream } = workflow.resume(["test input"], snapshotData);

	for await (const event of stream) {
		console.log(event.data);
	}
};

async function main() {
	await runWorkflow();
	await new Promise((resolve) => setTimeout(resolve, 2000));
	await resumeWorkflow();
}

main();

Summary by CodeRabbit

  • New Features

    • Introduced human-in-the-loop (HITL) support, enabling workflows to pause for and resume from human input.
    • Added the ability to save and restore workflow snapshots, allowing for workflow continuation after user responses.
    • Provided a CLI command execution tool and example workflow demonstrating HITL interactions.
    • New UI component for confirming CLI commands during HITL workflows.
    • Example server and documentation for running HITL workflows.
  • Enhancements

    • Improved chat and workflow handling to support pausing, resuming, and streaming with human input events.
    • Expanded utility exports for easier integration of HITL and streaming functionalities.
  • Documentation

    • Added README for HITL workflow example setup and usage instructions.

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/run-llama/create-llama/pull/686 **Author:** [@thucpn](https://github.com/thucpn) **Created:** 6/9/2025 **Status:** ✅ Merged **Merged:** 6/12/2025 **Merged by:** [@thucpn](https://github.com/thucpn) **Base:** `main` ← **Head:** `tp/hitl-for-ts` --- ### 📝 Commits (10+) - [`e4c07f9`](https://github.com/run-llama/create-llama/commit/e4c07f9699a62b285309779f2f9995fb01ef192b) feat: support human in the loop for TS - [`eba44a3`](https://github.com/run-llama/create-llama/commit/eba44a35f6f652e0fda247a507ec4bbb55269e34) add example for custom workflow - [`7875178`](https://github.com/run-llama/create-llama/commit/7875178d937a1a43d67acd630b9c3364f9ad53b7) fix: need to request humanResponseEvent to save missing step to snapshot - [`ac5a1ef`](https://github.com/run-llama/create-llama/commit/ac5a1ef13fa4f8ad88a1dfb7b9b91de4e07da977) refactor: human response data should be any - [`832f5b6`](https://github.com/run-llama/create-llama/commit/832f5b6bb5a5200f234ae1abd551f0c0d6f788ee) refactor runWorkflow function to support resume stream - [`23fdd51`](https://github.com/run-llama/create-llama/commit/23fdd514cc34c1aa2b1207efd754f5b9663721f6) refactor: hitl - [`7b21682`](https://github.com/run-llama/create-llama/commit/7b21682784362bbc261269ca240876b3e74415fe) fix: workflow - [`ddccbcf`](https://github.com/run-llama/create-llama/commit/ddccbcffabac1bceed9d47b2c6cfac0760bee87b) add summary event - [`45af254`](https://github.com/run-llama/create-llama/commit/45af25411c5f888236baf3521c21523eef8cce45) send tool event - [`be894df`](https://github.com/run-llama/create-llama/commit/be894dfb31331ac328ed2f1503a80d2501a4fe3c) use requestId from Vercel ### 📊 Changes **41 files changed** (+1653 additions, -91 deletions) <details> <summary>View changed files</summary> ➕ `.changeset/eight-moons-perform.md` (+6 -0) 📝 `packages/create-llama/e2e/python/resolve_dependencies.spec.ts` (+1 -0) 📝 `packages/create-llama/e2e/shared/llamaindexserver_template.spec.ts` (+1 -0) 📝 `packages/create-llama/e2e/typescript/resolve_dependencies.spec.ts` (+3 -1) 📝 `packages/create-llama/helpers/constant.ts` (+9 -0) 📝 `packages/create-llama/helpers/index.ts` (+3 -1) 📝 `packages/create-llama/helpers/types.ts` (+2 -1) 📝 `packages/create-llama/helpers/typescript.ts` (+2 -1) 📝 `packages/create-llama/questions/simple.ts` (+17 -2) ➕ `packages/create-llama/templates/components/ui/use-cases/hitl/cli_human_input.tsx` (+95 -0) ➕ `packages/create-llama/templates/components/use-cases/python/hitl/README-template.md` (+109 -0) ➕ `packages/create-llama/templates/components/use-cases/python/hitl/events.py` (+34 -0) ➕ `packages/create-llama/templates/components/use-cases/python/hitl/workflow.py` (+87 -0) ➕ `packages/create-llama/templates/components/use-cases/typescript/hitl/README-template.md` (+106 -0) ➕ `packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/events.ts` (+12 -0) ➕ `packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/tools.ts` (+20 -0) ➕ `packages/create-llama/templates/components/use-cases/typescript/hitl/src/app/workflow.ts` (+101 -0) 📝 `packages/create-llama/templates/types/llamaindexserver/nextjs/package.json` (+2 -2) 📝 `packages/server/README.md` (+1 -0) ➕ `packages/server/examples/hitl/README.md` (+172 -0) _...and 21 more files_ </details> ### 📄 Description Pattern: ```ts import { createWorkflow, workflowEvent } from "@llama-flow/core"; import { request, withSnapshot } from "@llama-flow/core/middleware/snapshot"; import fs from "fs"; ///////////// EVENTS ///////////// const startEvent = workflowEvent<string>({ debugLabel: "Start event", }); const humamInputEvent = workflowEvent<string>({ debugLabel: "Human input event", }); const humanResponseEvent = workflowEvent<string>({ debugLabel: "Human response event", }); const stopEvent = workflowEvent<string>({ debugLabel: "Stop event", }); ///////////// CLIENT CODE: WORKFLOW DEFINITION ///////////// const workflowFactory = () => { const workflow = withSnapshot(createWorkflow()); workflow.handle([startEvent], ({ data: startInput }) => { console.log("Start event---"); const shouldRequestHuman = startInput.length < 3; // condition to request human if (shouldRequestHuman) { // request human input with a reason return humamInputEvent.with("input length < 3"); } // if no need to request human, stop the workflow return stopEvent.with("Stop without request human"); }); workflow.handle([humanResponseEvent], ({ data: userInput }) => { // userInput is the input from human // we can trigger LLM with user input to get final result const sampleFinalResult = "Sample final result for human input: " + userInput; return stopEvent.with(sampleFinalResult); }); return workflow; }; ///////////// SERVER CODE: RUN & RESUME WORKFLOW ///////////// const runWorkflow = async () => { const workflow = workflowFactory(); const { sendEvent, stream, snapshot, onRequest } = workflow.createContext(); // try send a start event with empty input to trigger human input sendEvent(startEvent.with("")); // consume stream for await (const event of stream) { if (humamInputEvent.include(event)) { console.log("Need to request human input with reason: ", event.data); // send a request event sendEvent(request(humanResponseEvent)); // save snapshot const [_, snapshotData] = await snapshot(); console.log("Snapshot data: ", snapshotData); fs.writeFileSync("snapshot.json", JSON.stringify(snapshotData, null, 2)); // stop the workflow break; } console.log(event.data); } }; const resumeWorkflow = async () => { const workflow = workflowFactory(); const snapshotData = JSON.parse(fs.readFileSync("snapshot.json", "utf8")); const { stream } = workflow.resume(["test input"], snapshotData); for await (const event of stream) { console.log(event.data); } }; async function main() { await runWorkflow(); await new Promise((resolve) => setTimeout(resolve, 2000)); await resumeWorkflow(); } main(); ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced human-in-the-loop (HITL) support, enabling workflows to pause for and resume from human input. - Added the ability to save and restore workflow snapshots, allowing for workflow continuation after user responses. - Provided a CLI command execution tool and example workflow demonstrating HITL interactions. - New UI component for confirming CLI commands during HITL workflows. - Example server and documentation for running HITL workflows. - **Enhancements** - Improved chat and workflow handling to support pausing, resuming, and streaming with human input events. - Expanded utility exports for easier integration of HITL and streaming functionalities. - **Documentation** - Added README for HITL workflow example setup and usage instructions. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
yindo added the pull-request label 2026-02-15 20:15:51 -05:00
yindo closed this issue 2026-02-15 20:15:51 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: run-llama/create-llama#686