Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions tests/agents/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0

43 changes: 43 additions & 0 deletions tests/agents/jokeflow.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0

import asyncio

from llama_index.core.workflow import (
Event,
StartEvent,
StopEvent,
Workflow,
step,
)


class JokeEvent(Event):
joke: str


class JokeFlow(Workflow):
@step
async def generate_joke(self, ev: StartEvent) -> JokeEvent:
topic = ev.topic

response = "this is a joke about " + topic
asyncio.sleep(1)
return JokeEvent(joke=str(response))

@step
async def critique_joke(self, ev: JokeEvent) -> StopEvent:
joke = ev.joke

response = "this is a critique of the joke: " + joke
return StopEvent(result=str(response))


async def main():
w = JokeFlow(timeout=60, verbose=False)
result = await w.run(topic="pirates")
print(str(result))


if __name__ == "__main__":
asyncio.run(main())
70 changes: 70 additions & 0 deletions tests/agents/jokeflow_manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
{
"authors": ["Cisco Systems Inc."],
"annotations": {
"type": "llama-index"
},
"created_at": "2025-05-21T00:00:00Z",
"name": "org.agntcy.jokeflow",
"description": "create and review Jokes",
"version": "0.0.1",
"schema_version": "0.3.1",
"skills": [],
"locators": [],
"extensions": [{
"name": "oasf.agntcy.org/feature/runtime/manifest",
"data": {
"acp": {
"capabilities": {
"threads": false,
"interrupts": false,
"callbacks": false
},
"input": {
"properties": {
"topic": {
"description": "The topic of the Joke",
"title": "topic",
"type": "string"
}
},
"required": ["topic"],
"title": "StartEvent",
"type": "object"
},
"output": {
"properties": {
"joke": {
"description": "the created Joke",
"title": "joke",
"type": "string"
}
},
"required": ["joke"],
"title": "JokeEvent",
"type": "object"
},
"config": {
"properties": {},
"title": "ConfigSchema",
"type": "object"
}
},
"deployment": {
"deployment_options": [{
"type": "source_code",
"name": "source_code_local",
"url": "./../",
"framework_config": {
"framework_type": "llamaindex",
"path": "jokeflow:jokeflow_workflow"
}
}
],
"env_vars": [],
"dependencies": []
}
},
"version": "v0.2.2"
}
]
}
111 changes: 111 additions & 0 deletions tests/agents/jokereviewer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Copyright AGNTCY Contributors (https://github.com/agntcy)
# SPDX-License-Identifier: Apache-2.0
import asyncio

from dotenv import find_dotenv, load_dotenv
from llama_index.core.workflow import (
Context,
Event,
StartEvent,
StopEvent,
Workflow,
step,
)

load_dotenv(dotenv_path=find_dotenv(usecwd=True))


class SecondEvent(Event):
joke: str
ai_answer: str


class FirstInterruptEvent(Event):
joke: str
first_question: str
needs_answer: bool


class InterruptResponseEvent(Event):
answer: str


class JokeEvent(Event):
joke: str


class JokeReviewer(Workflow):
@step
async def generate_joke(self, ev: StartEvent) -> JokeEvent:
topic = ev.topic
response = "this is a joke about " + topic
await asyncio.sleep(1)
return JokeEvent(joke=str(response))

@step
async def step_interrupt_one(self, ctx: Context, ev: JokeEvent) -> SecondEvent:
print(f"> step_interrupt_one input : {ev.joke}")
await asyncio.sleep(1)
# wait until we see a HumanResponseEvent
needs_answer = True
response = await ctx.wait_for_event(
InterruptResponseEvent,
waiter_id="waiter_step_interrupt_one",
waiter_event=FirstInterruptEvent(
joke=ev.joke,
first_question=f"What is your review about the Joke '{ev.joke}'?",
needs_answer=needs_answer,
),
)

print(f"> receive response : {response.answer}")
if needs_answer and not response.answer:
raise ValueError("This needs a non-empty answer")

return SecondEvent(
joke=ev.joke, ai_answer=f"Received human answer: {response.answer}"
)

@step
async def critique_joke(self, ev: SecondEvent) -> StopEvent:
joke = ev.joke

await asyncio.sleep(1)
response = "this is a review for the joke: " + joke + "\n" + ev.ai_answer
result = {
joke: joke,
"review": str(response),
}
return StopEvent(result=result)


def interrupt_workflow() -> JokeReviewer:
joke_reviewer = JokeReviewer(timeout=None, verbose=True)
return joke_reviewer


async def main():
print("Joke Reviewer with Interrupts")
workflow = interrupt_workflow()

handler = workflow.run(topic="pirates")

print("Reading events from the workflow...")
async for ev in handler.stream_events():
if isinstance(ev, FirstInterruptEvent):
# capture keyboard input
response = input(ev.first_question)
print("Sending response event...")
handler.ctx.send_event(
InterruptResponseEvent(
answer=response,
)
)

print("waiting for final result...")
final_result = await handler
print("Final result: ", final_result)


if __name__ == "__main__":
asyncio.run(main())
129 changes: 129 additions & 0 deletions tests/agents/jokereviewer_manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
{
"authors": ["Cisco Systems Inc."],
"annotations": {
"type": "llama-index"
},
"created_at": "2025-05-21T00:00:00Z",
"name": "org.agntcy.jokereviewer",
"description": "create and review Jokes",
"version": "0.0.1",
"schema_version": "0.3.1",
"skills": [],
"locators": [],
"extensions": [{
"name": "oasf.agntcy.org/feature/runtime/manifest",
"data": {
"acp": {
"input": {
"type": "object",
"properties": {
"input": {
"type": "string",
"description": "The human input"
}
}
},
"output": {
"type": "object",
"oneOf": [{
"properties": {
"human_answer": {
"type": "string"
}
},
"required": [
"human_answer"
]
}, {
"properties": {
"ai_answer": {
"type": "string"
}
},
"required": [
"ai_answer"
]
}
]
},
"config": {
"type": "object",
"properties": {}
},
"capabilities": {
"threads": false,
"interrupts": true,
"callbacks": false
},
"interrupts": [{
"interrupt_type": "first_interrupt",
"interrupt_payload": {
"type": "object",
"title": "First interrupt",
"description": "First interrupt the agent is asking",
"properties": {
"joke": {
"title": "Joke",
"description": "The joke to be reviewed",
"type": "string"
},
"first_question": {
"title": "First question",
"description": "Natural language question that is going to be asked by this agent",
"type": "string"
},
"needs_answer": {
"title": "Whether the agent needs an answer for this question",
"description": "True if the agent needs a non-empty answer for this question, False otherwise",
"type": "boolean"
}
},
"required": [
"joke",
"first_question",
"needs_answer"
]
},
"resume_payload": {
"type": "object",
"title": "First interrupt answer",
"description": "Answer to the first interrupt the agent asked",
"properties": {
"answer": {
"title": "Answer",
"description": "Text of the answer",
"type": "string"
}
},
"required": [
"answer"
]
}
}
]
},
"dependencies": [],
"deployment": {
"dependencies": [],
"deployment_options": [{
"type": "source_code",
"name": "source_code_local",
"url": "file://.",
"framework_config": {
"framework_type": "llamaindex",
"path": "JokeReviewer",
"interrupts": {
"first_interrupt": {
"interrupt_ref": "tests.agents.jokereviewer:FirstInterruptEvent",
"resume_ref": "tests.agents.jokereviewer:InterruptResponseEvent"
}
}
}
}
]
}
},
"version": "v0.2.2"
}
]
}
Loading