State in Custom Function
This example demonstrates how to access the run context in a custom python function step
Create a Python file
Create a file named access_session_state_in_custom_python_function_step.py
Add code to file
1from kern.agent import Agent2from kern.db.sqlite import SqliteDb3from kern.models.openai import OpenAIResponses4from kern.run import RunContext5from kern.team import Team6from kern.tools.hackernews import HackerNewsTools7from kern.tools.yfinance import YFinanceTools8from kern.workflow.step import Step, StepInput, StepOutput9from kern.workflow.workflow import Workflow1011# Define agents12hackernews_agent = Agent(13 name="Hackernews Agent",14 model=OpenAIResponses(id="gpt-5.2"),15 tools=[HackerNewsTools()],16 instructions="Extract key insights and content from Hackernews posts",17)1819finance_agent = Agent(20 name="Finance Agent",21 model=OpenAIResponses(id="gpt-5.2"),22 tools=[YFinanceTools()],23 instructions="Get financial data and market trends",24)2526# Define research team for complex analysis27research_team = Team(28 name="Research Team",29 model=OpenAIResponses(id="gpt-5.2"),30 members=[hackernews_agent, finance_agent],31 instructions="Analyze content and create comprehensive social media strategy",32)3334content_planner = Agent(35 name="Content Planner",36 model=OpenAIResponses(id="gpt-5.2"),37 instructions=[38 "Plan a content schedule over 4 weeks for the provided topic and research content",39 "Ensure that I have posts for 3 posts per week",40 ],41)424344def custom_content_planning_function(45 step_input: StepInput, run_context: RunContext46) -> StepOutput:47 """48 Custom function that does intelligent content planning with context awareness49 and maintains a content plan history in session_state50 """51 message = step_input.input52 previous_step_content = step_input.previous_step_content5354 # Initialize content history if not present55 if "content_plans" not in run_context.session_state:56 run_context.session_state["content_plans"] = []5758 if "plan_counter" not in run_context.session_state:59 run_context.session_state["plan_counter"] = 06061 # Increment plan counter62 run_context.session_state["plan_counter"] += 163 current_plan_id = run_context.session_state["plan_counter"]6465 # Create intelligent planning prompt66 planning_prompt = f"""67 STRATEGIC CONTENT PLANNING REQUEST:6869 Core Topic: {message}70 Plan ID: #{current_plan_id}7172 Research Results: {previous_step_content[:500] if previous_step_content else "No research results"}7374 Previous Plans Count: {len(run_context.session_state["content_plans"])}7576 Planning Requirements:77 1. Create a comprehensive content strategy based on the research78 2. Leverage the research findings effectively79 3. Identify content formats and channels80 4. Provide timeline and priority recommendations81 5. Include engagement and distribution strategies8283 Please create a detailed, actionable content plan.84 """8586 try:87 response = content_planner.run(planning_prompt)8889 # Store this plan in session state90 plan_data = {91 "id": current_plan_id,92 "topic": message,93 "content": response.content,94 "timestamp": f"Plan #{current_plan_id}",95 "has_research": bool(previous_step_content),96 }97 run_context.session_state["content_plans"].append(plan_data)9899 enhanced_content = f"""100 ## Strategic Content Plan #{current_plan_id}101102 **Planning Topic:** {message}103104 **Research Integration:** {"Research-based" if previous_step_content else "No research foundation"}105 **Total Plans Created:** {len(run_context.session_state["content_plans"])}106107 **Content Strategy:**108 {response.content}109110 **Custom Planning Enhancements:**111 - Research Integration: {"High" if previous_step_content else "Baseline"}112 - Strategic Alignment: Optimized for multi-channel distribution113 - Execution Ready: Detailed action items included114 - Session History: {len(run_context.session_state["content_plans"])} plans stored115116 **Plan ID:** #{current_plan_id}117 """.strip()118119 return StepOutput(content=enhanced_content)120121 except Exception as e:122 return StepOutput(123 content=f"Custom content planning failed: {str(e)}",124 success=False,125 )126127128def content_summary_function(step_input: StepInput, run_context: RunContext) -> StepOutput:129 """130 Custom function that summarizes all content plans created in the session131 """132 if run_context.session_state is None or run_context.session_state.get("content_plans") is None:133 return StepOutput(134 content="No content plans found in session state.", success=False135 )136137 plans = run_context.session_state["content_plans"]138 summary = f"""139 ## Content Planning Session Summary140141 **Total Plans Created:** {len(plans)}142 **Session Statistics:**143 - Plans with research: {len([p for p in plans if p["has_research"]])}144 - Plans without research: {len([p for p in plans if not p["has_research"]])}145146 **Plan Overview:**147 """148149 for plan in plans:150 summary += f"""151152 ### Plan #{plan["id"]} - {plan["topic"]}153 - Research Available: {"Yes" if plan["has_research"] else "No"}154 - Status: Completed155 """156157 # Update session state with summary info158 run_context.session_state["session_summarized"] = True159 run_context.session_state["total_plans_summarized"] = len(plans)160161 return StepOutput(content=summary.strip())162163164# Define steps using different executor types165166research_step = Step(167 name="Research Step",168 team=research_team,169)170171content_planning_step = Step(172 name="Content Planning Step",173 executor=custom_content_planning_function,174)175176content_summary_step = Step(177 name="Content Summary Step",178 executor=content_summary_function,179)180181182# Define and use examples183if __name__ == "__main__":184 content_creation_workflow = Workflow(185 name="Content Creation Workflow",186 description="Automated content creation with custom execution options and session state",187 db=SqliteDb(188 session_table="workflow_session",189 db_file="tmp/workflow.db",190 ),191 # Define the sequence of steps192 # First run the research_step, then the content_planning_step, then the summary_step193 # You can mix and match agents, teams, and even regular python functions directly as steps194 steps=[research_step, content_planning_step, content_summary_step],195 # Initialize session state with empty content plans196 session_state={"content_plans": [], "plan_counter": 0},197 )198199 print("=== First Workflow Run ===")200 content_creation_workflow.print_response(201 input="AI trends in 2024",202 markdown=True,203 )204205 print(206 f"\nSession State After First Run: {content_creation_workflow.get_session_state()}"207 )208209 print("\n" + "=" * 60 + "\n")210211 print("=== Second Workflow Run (Same Session) ===")212 content_creation_workflow.print_response(213 input="Machine Learning automation tools",214 markdown=True,215 )216217 print(f"\nFinal Session State: {content_creation_workflow.get_session_state()}")Set up your virtual environment
1uv venv --python 3.122source .venv/bin/activate1uv venv --python 3.122.venv\Scripts\activateInstall dependencies
1uv pip install -U kern-ai openai yfinanceExport your OpenAI API key
Set OpenAI Key
Set your OPENAI_API_KEY as an environment variable. You can get one from OpenAI.
1export OPENAI_API_KEY=sk-***1setx OPENAI_API_KEY sk-***Run Workflow
1python access_session_state_in_custom_python_function_step.py