agnt5 0.2.8a4__cp310-abi3-manylinux_2_34_x86_64.whl → 0.2.8a5__cp310-abi3-manylinux_2_34_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of agnt5 might be problematic. Click here for more details.

agnt5/__init__.py CHANGED
@@ -26,9 +26,10 @@ from .exceptions import (
26
26
  ExecutionError,
27
27
  RetryError,
28
28
  StateError,
29
+ WaitingForUserInputException,
29
30
  )
30
31
  from .function import FunctionRegistry, function
31
- from .tool import Tool, ToolRegistry, tool
32
+ from .tool import AskUserTool, RequestApprovalTool, Tool, ToolRegistry, tool
32
33
  from .types import BackoffPolicy, BackoffType, FunctionConfig, RetryPolicy, WorkflowConfig
33
34
  from .version import _get_version
34
35
  from .worker import Worker
@@ -62,6 +63,8 @@ __all__ = [
62
63
  "tool",
63
64
  "Tool",
64
65
  "ToolRegistry",
66
+ "AskUserTool",
67
+ "RequestApprovalTool",
65
68
  "agent",
66
69
  "Agent",
67
70
  "AgentRegistry",
@@ -81,6 +84,7 @@ __all__ = [
81
84
  "RetryError",
82
85
  "StateError",
83
86
  "CheckpointError",
87
+ "WaitingForUserInputException",
84
88
  "RunError",
85
89
  # Language Model (Simplified API)
86
90
  "lm",
agnt5/_core.abi3.so CHANGED
Binary file
agnt5/agent.py CHANGED
@@ -9,6 +9,7 @@ from __future__ import annotations
9
9
  import functools
10
10
  import json
11
11
  import logging
12
+ import time
12
13
  from typing import Any, Callable, Dict, List, Optional
13
14
 
14
15
  from .context import Context
@@ -221,10 +222,10 @@ class AgentContext(Context):
221
222
  for msg in messages:
222
223
  messages_data.append({
223
224
  "role": msg.role.value if hasattr(msg.role, 'value') else str(msg.role),
224
- "content": msg.content
225
+ "content": msg.content,
226
+ "timestamp": time.time() # Add timestamp for each message
225
227
  })
226
228
 
227
- import time
228
229
  entity_type = "AgentSession"
229
230
  entity_key = self._entity_key
230
231
 
agnt5/exceptions.py CHANGED
@@ -1,5 +1,7 @@
1
1
  """AGNT5 SDK exceptions and error types."""
2
2
 
3
+ from typing import Dict, List, Optional
4
+
3
5
 
4
6
  class AGNT5Error(Exception):
5
7
  """Base exception for all AGNT5 SDK errors."""
@@ -44,3 +46,44 @@ class NotImplementedError(AGNT5Error):
44
46
  """Raised when a feature is not yet implemented."""
45
47
 
46
48
  pass
49
+
50
+
51
+ class WaitingForUserInputException(AGNT5Error):
52
+ """Raised when workflow needs to pause for user input.
53
+
54
+ This exception is used internally by ctx.wait_for_user() to signal
55
+ that a workflow execution should pause and wait for user input.
56
+
57
+ The platform catches this exception and:
58
+ 1. Saves the workflow checkpoint state
59
+ 2. Returns awaiting_user_input status to the client
60
+ 3. Presents the question and options to the user
61
+ 4. Resumes execution when user responds
62
+
63
+ Attributes:
64
+ question: The question to ask the user
65
+ input_type: Type of input ("text", "approval", or "choice")
66
+ options: List of options for approval/choice inputs
67
+ checkpoint_state: Current workflow state for resume
68
+ """
69
+
70
+ def __init__(
71
+ self,
72
+ question: str,
73
+ input_type: str,
74
+ options: Optional[List[Dict]],
75
+ checkpoint_state: Dict,
76
+ ) -> None:
77
+ """Initialize WaitingForUserInputException.
78
+
79
+ Args:
80
+ question: Question to ask the user
81
+ input_type: Type of input - "text", "approval", or "choice"
82
+ options: List of option dicts (for approval/choice)
83
+ checkpoint_state: Workflow state snapshot for resume
84
+ """
85
+ super().__init__(f"Waiting for user input: {question}")
86
+ self.question = question
87
+ self.input_type = input_type
88
+ self.options = options or []
89
+ self.checkpoint_state = checkpoint_state
agnt5/tool.py CHANGED
@@ -416,3 +416,152 @@ def tool(
416
416
  if _func is None:
417
417
  return decorator
418
418
  return decorator(_func)
419
+
420
+
421
+ # ============================================================================
422
+ # Built-in Human-in-the-Loop Tools
423
+ # ============================================================================
424
+
425
+ class AskUserTool(Tool):
426
+ """
427
+ Built-in tool that agents can use to request text input from users.
428
+
429
+ This tool pauses the workflow execution and waits for the user to provide
430
+ a text response. The workflow resumes when the user submits their input.
431
+
432
+ Example:
433
+ ```python
434
+ from agnt5 import Agent, workflow, WorkflowContext
435
+ from agnt5.tool import AskUserTool
436
+
437
+ @workflow(chat=True)
438
+ async def agent_with_hitl(ctx: WorkflowContext, query: str) -> dict:
439
+ agent = Agent(
440
+ name="research_agent",
441
+ model="openai/gpt-4o-mini",
442
+ instructions="You are a research assistant.",
443
+ tools=[AskUserTool(ctx)]
444
+ )
445
+
446
+ result = await agent.run(query, context=ctx)
447
+ return {"response": result.output}
448
+ ```
449
+ """
450
+
451
+ def __init__(self, context: "WorkflowContext"): # type: ignore
452
+ """
453
+ Initialize AskUserTool.
454
+
455
+ Args:
456
+ context: Workflow context with wait_for_user capability
457
+ """
458
+ # Import here to avoid circular dependency
459
+ from .workflow import WorkflowContext
460
+
461
+ if not isinstance(context, WorkflowContext):
462
+ raise ConfigurationError(
463
+ "AskUserTool requires a WorkflowContext. "
464
+ "This tool can only be used within workflows."
465
+ )
466
+
467
+ super().__init__(
468
+ name="ask_user",
469
+ description="Ask the user a question and wait for their text response",
470
+ handler=self._handler,
471
+ auto_schema=True
472
+ )
473
+ self.context = context
474
+
475
+ async def _handler(self, ctx: Context, question: str) -> str:
476
+ """
477
+ Ask user a question and wait for their response.
478
+
479
+ Args:
480
+ ctx: Execution context (unused, required by Tool signature)
481
+ question: Question to ask the user
482
+
483
+ Returns:
484
+ User's text response
485
+ """
486
+ return await self.context.wait_for_user(question, input_type="text")
487
+
488
+
489
+ class RequestApprovalTool(Tool):
490
+ """
491
+ Built-in tool that agents can use to request approval from users.
492
+
493
+ This tool pauses the workflow execution and presents an approval request
494
+ to the user with approve/reject options. The workflow resumes when the
495
+ user makes a decision.
496
+
497
+ Example:
498
+ ```python
499
+ from agnt5 import Agent, workflow, WorkflowContext
500
+ from agnt5.tool import RequestApprovalTool
501
+
502
+ @workflow(chat=True)
503
+ async def deployment_agent(ctx: WorkflowContext, changes: dict) -> dict:
504
+ agent = Agent(
505
+ name="deploy_agent",
506
+ model="openai/gpt-4o-mini",
507
+ instructions="You help deploy code changes safely.",
508
+ tools=[RequestApprovalTool(ctx)]
509
+ )
510
+
511
+ result = await agent.run(
512
+ f"Review and deploy these changes: {changes}",
513
+ context=ctx
514
+ )
515
+ return {"response": result.output}
516
+ ```
517
+ """
518
+
519
+ def __init__(self, context: "WorkflowContext"): # type: ignore
520
+ """
521
+ Initialize RequestApprovalTool.
522
+
523
+ Args:
524
+ context: Workflow context with wait_for_user capability
525
+ """
526
+ # Import here to avoid circular dependency
527
+ from .workflow import WorkflowContext
528
+
529
+ if not isinstance(context, WorkflowContext):
530
+ raise ConfigurationError(
531
+ "RequestApprovalTool requires a WorkflowContext. "
532
+ "This tool can only be used within workflows."
533
+ )
534
+
535
+ super().__init__(
536
+ name="request_approval",
537
+ description="Request user approval for an action before proceeding",
538
+ handler=self._handler,
539
+ auto_schema=True
540
+ )
541
+ self.context = context
542
+
543
+ async def _handler(self, ctx: Context, action: str, details: str = "") -> str:
544
+ """
545
+ Request approval from user for an action.
546
+
547
+ Args:
548
+ ctx: Execution context (unused, required by Tool signature)
549
+ action: The action requiring approval
550
+ details: Additional details about the action
551
+
552
+ Returns:
553
+ "approve" or "reject" based on user's decision
554
+ """
555
+ question = f"Action: {action}"
556
+ if details:
557
+ question += f"\n\nDetails:\n{details}"
558
+ question += "\n\nDo you approve?"
559
+
560
+ return await self.context.wait_for_user(
561
+ question,
562
+ input_type="approval",
563
+ options=[
564
+ {"id": "approve", "label": "Approve"},
565
+ {"id": "reject", "label": "Reject"}
566
+ ]
567
+ )
agnt5/worker.py CHANGED
@@ -5,6 +5,7 @@ from __future__ import annotations
5
5
  import asyncio
6
6
  import contextvars
7
7
  import logging
8
+ import uuid
8
9
  from typing import Any, Dict, List, Optional
9
10
 
10
11
  from .function import FunctionRegistry
@@ -758,16 +759,31 @@ class Worker:
758
759
  """Execute a workflow handler with automatic replay support."""
759
760
  import json
760
761
  from .workflow import WorkflowEntity, WorkflowContext
761
- from .entity import _get_state_adapter
762
+ from .entity import _get_state_adapter, _entity_state_adapter_ctx
763
+ from .exceptions import WaitingForUserInputException
762
764
  from ._core import PyExecuteComponentResponse
763
765
 
766
+ # Set entity state adapter in context so workflows can use Entities
767
+ _entity_state_adapter_ctx.set(self._entity_state_adapter)
768
+
764
769
  try:
765
770
  # Parse input data
766
771
  input_dict = json.loads(input_data.decode("utf-8")) if input_data else {}
767
772
 
773
+ # Extract or generate session_id for multi-turn conversation support (for chat workflows)
774
+ # If session_id is provided, the workflow can maintain conversation context
775
+ session_id = input_dict.get("session_id")
776
+
777
+ if not session_id:
778
+ session_id = str(uuid.uuid4())
779
+ logger.info(f"Created new workflow session: {session_id}")
780
+ else:
781
+ logger.info(f"Using existing workflow session: {session_id}")
782
+
768
783
  # Parse replay data from request metadata for crash recovery
769
784
  completed_steps = {}
770
785
  initial_state = {}
786
+ user_response = None
771
787
 
772
788
  if hasattr(request, 'metadata') and request.metadata:
773
789
  # Parse completed steps for replay
@@ -790,6 +806,11 @@ class Worker:
790
806
  except json.JSONDecodeError:
791
807
  logger.warning("Failed to parse workflow_state from metadata")
792
808
 
809
+ # Check for user response (workflow resume after pause)
810
+ if "user_response" in request.metadata:
811
+ user_response = request.metadata["user_response"]
812
+ logger.info(f"▶️ Resuming workflow with user response: {user_response}")
813
+
793
814
  # Create WorkflowEntity for state management
794
815
  workflow_entity = WorkflowEntity(run_id=f"{self.service_name}:{config.name}")
795
816
 
@@ -798,6 +819,11 @@ class Worker:
798
819
  workflow_entity._completed_steps = completed_steps
799
820
  logger.debug(f"Loaded {len(completed_steps)} completed steps into workflow entity")
800
821
 
822
+ # Inject user response if resuming from pause
823
+ if user_response:
824
+ workflow_entity.inject_user_response(user_response)
825
+ logger.debug(f"Injected user response into workflow entity")
826
+
801
827
  if initial_state:
802
828
  # Load initial state into entity's state adapter
803
829
  state_adapter = _get_state_adapter()
@@ -860,13 +886,70 @@ class Worker:
860
886
 
861
887
  logger.info(f"Workflow completed successfully with {len(step_events)} steps")
862
888
 
889
+ # Add session_id to metadata for multi-turn conversation support
890
+ metadata["session_id"] = session_id
891
+
863
892
  return PyExecuteComponentResponse(
864
893
  invocation_id=request.invocation_id,
865
894
  success=True,
866
895
  output_data=output_data,
867
896
  state_update=None, # Not used for workflows (use metadata instead)
868
897
  error_message=None,
869
- metadata=metadata if metadata else None, # Include step events + state
898
+ metadata=metadata if metadata else None, # Include step events + state + session_id
899
+ is_chunk=False,
900
+ done=True,
901
+ chunk_index=0,
902
+ )
903
+
904
+ except WaitingForUserInputException as e:
905
+ # Workflow paused for user input
906
+ logger.info(f"⏸️ Workflow paused waiting for user input: {e.question}")
907
+
908
+ # Collect metadata for pause state
909
+ # Note: All metadata values must be strings for Rust FFI
910
+ pause_metadata = {
911
+ "status": "awaiting_user_input",
912
+ "question": e.question,
913
+ "input_type": e.input_type,
914
+ }
915
+
916
+ # Add optional fields only if they exist
917
+ if e.options:
918
+ pause_metadata["options"] = json.dumps(e.options)
919
+ if e.checkpoint_state:
920
+ pause_metadata["checkpoint_state"] = json.dumps(e.checkpoint_state)
921
+ if session_id:
922
+ pause_metadata["session_id"] = session_id
923
+
924
+ # Add step events to pause metadata for durability
925
+ step_events = ctx._workflow_entity._step_events
926
+ if step_events:
927
+ pause_metadata["step_events"] = json.dumps(step_events)
928
+ logger.debug(f"Paused workflow has {len(step_events)} recorded steps")
929
+
930
+ # Add current workflow state to pause metadata
931
+ if hasattr(ctx, '_workflow_entity') and ctx._workflow_entity._state is not None:
932
+ if ctx._workflow_entity._state.has_changes():
933
+ state_snapshot = ctx._workflow_entity._state.get_state_snapshot()
934
+ pause_metadata["workflow_state"] = json.dumps(state_snapshot)
935
+ logger.debug(f"Paused workflow state snapshot: {state_snapshot}")
936
+
937
+ # Return "success" with awaiting_user_input metadata
938
+ # The output contains the question details for the client
939
+ output = {
940
+ "question": e.question,
941
+ "input_type": e.input_type,
942
+ "options": e.options,
943
+ }
944
+ output_data = json.dumps(output).encode("utf-8")
945
+
946
+ return PyExecuteComponentResponse(
947
+ invocation_id=request.invocation_id,
948
+ success=True, # This is a valid pause state, not an error
949
+ output_data=output_data,
950
+ state_update=None,
951
+ error_message=None,
952
+ metadata=pause_metadata,
870
953
  is_chunk=False,
871
954
  done=True,
872
955
  chunk_index=0,
agnt5/workflow.py CHANGED
@@ -7,7 +7,7 @@ import functools
7
7
  import inspect
8
8
  import logging
9
9
  import uuid
10
- from typing import Any, Callable, Dict, Optional, TypeVar, cast
10
+ from typing import Any, Callable, Dict, List, Optional, TypeVar, cast
11
11
 
12
12
  from ._schema_utils import extract_function_metadata, extract_function_schemas
13
13
  from .context import Context
@@ -254,6 +254,86 @@ class WorkflowContext(Context):
254
254
 
255
255
  return result
256
256
 
257
+ async def wait_for_user(
258
+ self,
259
+ question: str,
260
+ input_type: str = "text",
261
+ options: Optional[List[Dict]] = None
262
+ ) -> str:
263
+ """
264
+ Pause workflow execution and wait for user input.
265
+
266
+ On replay (even after worker crash), resumes from this point
267
+ with the user's response. This method enables human-in-the-loop
268
+ workflows by pausing execution and waiting for user interaction.
269
+
270
+ Args:
271
+ question: Question to ask the user
272
+ input_type: Type of input - "text", "approval", or "choice"
273
+ options: For approval/choice, list of option dicts with 'id' and 'label'
274
+
275
+ Returns:
276
+ User's response string
277
+
278
+ Raises:
279
+ WaitingForUserInputException: When no cached response exists (first call)
280
+
281
+ Example (text input):
282
+ ```python
283
+ city = await ctx.wait_for_user("Which city?")
284
+ ```
285
+
286
+ Example (approval):
287
+ ```python
288
+ decision = await ctx.wait_for_user(
289
+ "Approve this action?",
290
+ input_type="approval",
291
+ options=[
292
+ {"id": "approve", "label": "Approve"},
293
+ {"id": "reject", "label": "Reject"}
294
+ ]
295
+ )
296
+ ```
297
+
298
+ Example (choice):
299
+ ```python
300
+ model = await ctx.wait_for_user(
301
+ "Which model?",
302
+ input_type="choice",
303
+ options=[
304
+ {"id": "gpt4", "label": "GPT-4"},
305
+ {"id": "claude", "label": "Claude"}
306
+ ]
307
+ )
308
+ ```
309
+ """
310
+ from .exceptions import WaitingForUserInputException
311
+
312
+ # Generate unique step name for this user input request
313
+ # Using run_id ensures uniqueness across workflow execution
314
+ response_key = f"user_response:{self.run_id}"
315
+
316
+ # Check if we already have the user's response (replay scenario)
317
+ if self._workflow_entity.has_completed_step(response_key):
318
+ response = self._workflow_entity.get_completed_step(response_key)
319
+ self._logger.info("🔄 Replaying user response from checkpoint")
320
+ return response
321
+
322
+ # No response yet - pause execution
323
+ # Collect current workflow state for checkpoint
324
+ checkpoint_state = {}
325
+ if hasattr(self._workflow_entity, '_state') and self._workflow_entity._state is not None:
326
+ checkpoint_state = self._workflow_entity._state.get_state_snapshot()
327
+
328
+ self._logger.info(f"⏸️ Pausing workflow for user input: {question}")
329
+
330
+ raise WaitingForUserInputException(
331
+ question=question,
332
+ input_type=input_type,
333
+ options=options,
334
+ checkpoint_state=checkpoint_state
335
+ )
336
+
257
337
 
258
338
  # ============================================================================
259
339
  # WorkflowEntity: Entity specialized for workflow execution state
@@ -337,6 +417,26 @@ class WorkflowEntity(Entity):
337
417
  """Check if step has been completed."""
338
418
  return step_name in self._completed_steps
339
419
 
420
+ def inject_user_response(self, response: str) -> None:
421
+ """
422
+ Inject user response as a completed step for workflow resume.
423
+
424
+ This method is called by the worker when resuming a paused workflow
425
+ with the user's response. It stores the response as if it was a
426
+ completed step, allowing wait_for_user() to retrieve it on replay.
427
+
428
+ Args:
429
+ response: User's response to inject
430
+
431
+ Example:
432
+ # Platform resumes workflow with user response
433
+ workflow_entity.inject_user_response("yes")
434
+ # On replay, wait_for_user() returns "yes" from cache
435
+ """
436
+ response_key = f"user_response:{self.run_id}"
437
+ self._completed_steps[response_key] = response
438
+ logger.info(f"Injected user response for {self.run_id}: {response}")
439
+
340
440
  @property
341
441
  def state(self) -> "WorkflowState":
342
442
  """
@@ -408,6 +508,14 @@ class WorkflowState(EntityState):
408
508
  "deleted": True
409
509
  })
410
510
 
511
+ def has_changes(self) -> bool:
512
+ """Check if any state changes have been tracked."""
513
+ return len(self._workflow_entity._state_changes) > 0
514
+
515
+ def get_state_snapshot(self) -> Dict[str, Any]:
516
+ """Get current state as a snapshot dictionary."""
517
+ return dict(self._state)
518
+
411
519
 
412
520
  class WorkflowRegistry:
413
521
  """Registry for workflow handlers."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agnt5
3
- Version: 0.2.8a4
3
+ Version: 0.2.8a5
4
4
  Classifier: Development Status :: 3 - Alpha
5
5
  Classifier: Intended Audience :: Developers
6
6
  Classifier: Programming Language :: Python :: 3
@@ -1,22 +1,22 @@
1
- agnt5-0.2.8a4.dist-info/METADATA,sha256=Dp8yJo_dx5B79OM0ptGgR80TjCUbyovpSc4Pt57dfuY,996
2
- agnt5-0.2.8a4.dist-info/WHEEL,sha256=AdMozAxftELsa3nYun92mL1tYO-R1ewuDPju53zvoK0,107
3
- agnt5/__init__.py,sha256=ACkK91EPdnv5tYip09QCZ9rfV4iBKzNjGfYVLJD1XGg,2045
1
+ agnt5-0.2.8a5.dist-info/METADATA,sha256=0yneaLrJFbpRR65wwR3XBaUy-KsJDFoi191gMrC1558,996
2
+ agnt5-0.2.8a5.dist-info/WHEEL,sha256=AdMozAxftELsa3nYun92mL1tYO-R1ewuDPju53zvoK0,107
3
+ agnt5/__init__.py,sha256=liMb9egh56qvgY4Xvs9s7grOzF3lXSE8-nIksJLNAy4,2195
4
4
  agnt5/_compat.py,sha256=BGuy3v5VDOHVa5f3Z-C22iMN19lAt0mPmXwF3qSSWxI,369
5
- agnt5/_core.abi3.so,sha256=CNmJC1AYLy8dABLguVfaWM6YqaTswjRnUZwM_07MXyk,15859720
5
+ agnt5/_core.abi3.so,sha256=bMEWMgxWbi0KGt-9BJC34QqwWY3BHrHKQi_jgsDlmFU,15861440
6
6
  agnt5/_retry_utils.py,sha256=loHsWY5BR4wZy57IzcDEjQAy88DHVwVIr25Cn1d9GPA,5801
7
7
  agnt5/_schema_utils.py,sha256=MR67RW757T4Oq2Jqf4kB61H_b51zwaf3CLWELnkngRo,9572
8
8
  agnt5/_telemetry.py,sha256=bIY9AvBRjJBTHoBPbfR6X1OgaiUf-T0vCoi0_snsWXA,5957
9
- agnt5/agent.py,sha256=aBrhtPaUAHOHv3-h_Yb2UMqFHertr1P2hJ7fA_4IXcw,43225
9
+ agnt5/agent.py,sha256=PuRq4cA8kJrBgrjRuDu62GBKJwefEjvndJZOj78_OGg,43293
10
10
  agnt5/client.py,sha256=kXksazgxdVXWaG9OkjJA4cWruNtcS-ENhtnkrIdw-Nk,23212
11
11
  agnt5/context.py,sha256=S2OzPkhn_jnqSWfT21mSYOux8vHaLKQxcAvggZDHQek,2378
12
12
  agnt5/entity.py,sha256=AlHmSHVxQD5EYBvkmERKUkwv0ERrKaT8rvRK611hv_I,28941
13
- agnt5/exceptions.py,sha256=mZ0q-NK6OKhYxgwBJpIbgpgzk-CJaFIHDbp1EE-pS7I,925
13
+ agnt5/exceptions.py,sha256=2YB7o6B0FBW2S7x47HnV-HaaEYVSsjRDAdZ9_MSD8Tw,2431
14
14
  agnt5/function.py,sha256=f1vaAlJRwuo8cxCOGEd8XPido00mOhlPS8UJJx-6hJI,11041
15
15
  agnt5/lm.py,sha256=9dFjd6eQ3f3lFZe7H7rWZherYiP_58MT1F5xpwD8PCg,23195
16
- agnt5/tool.py,sha256=uc4L-Q9QyLzQDe-MZKk2Wo3o5e-mK8tfaQwVDgQdouQ,13133
16
+ agnt5/tool.py,sha256=dkShd97Y1cwSOUnTwvL2gr0CW-usRlaq4frki9kREXI,18008
17
17
  agnt5/tracing.py,sha256=Mh2-OfnQM61lM_P8gxJstafdsUA8Gxoo1lP-Joxhub8,5980
18
18
  agnt5/types.py,sha256=Zb71ZMwvrt1p4SH18cAKunp2y5tao_W5_jGYaPDejQo,2840
19
19
  agnt5/version.py,sha256=rOq1mObLihnnKgKqBrwZA0zwOPudEKVFcW1a48ynkqc,573
20
- agnt5/worker.py,sha256=NflbueeL2LT8NGywTQnEv1r-N8f54AENWcZARJ5wO8o,47975
21
- agnt5/workflow.py,sha256=3s9CY6a4UkJZ9YyHv2SAkY3UeCVBlfVi7jxJMFi8Dhg,19488
22
- agnt5-0.2.8a4.dist-info/RECORD,,
20
+ agnt5/worker.py,sha256=W5_yvy1vcflYjoPAGcIirbHXMbEXijXPJtGQOgl6oz4,51815
21
+ agnt5/workflow.py,sha256=cDxKK21mLrsgjLGmosinhKnAme30CoQqs_fUFvRsyI0,23456
22
+ agnt5-0.2.8a5.dist-info/RECORD,,