boundflow 0.6.0__tar.gz → 0.7.0.dev7__tar.gz

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.
Files changed (122) hide show
  1. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/PKG-INFO +1 -1
  2. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/policies.py +20 -0
  3. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/control_plane.py +33 -0
  4. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/ui/labels.py +2 -0
  5. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/ui/render.py +11 -5
  6. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/ui/server.py +9 -3
  7. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/ui/views.py +137 -1
  8. boundflow-0.7.0.dev7/boundflow/v1/lifecycle_pb2.py +201 -0
  9. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/lifecycle_pb2_grpc.py +43 -0
  10. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/PKG-INFO +1 -1
  11. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/pyproject.toml +1 -1
  12. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_interrupted_run_metrics.py +29 -7
  13. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_ui_console.py +187 -3
  14. boundflow-0.6.0/boundflow/v1/lifecycle_pb2.py +0 -195
  15. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/LICENSE +0 -0
  16. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/__init__.py +0 -0
  17. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/_transport.py +0 -0
  18. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/anthropic_client.py +0 -0
  19. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/__init__.py +0 -0
  20. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/__main__.py +0 -0
  21. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/_client.py +0 -0
  22. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/__init__.py +0 -0
  23. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/audit.py +0 -0
  24. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/pricing.py +0 -0
  25. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/tenants.py +0 -0
  26. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/commands/workflows.py +0 -0
  27. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/cli/output.py +0 -0
  28. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/errors.py +0 -0
  29. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/__init__.py +0 -0
  30. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/approval_gate.py +0 -0
  31. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/governed_langgraph.py +0 -0
  32. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/hello.py +0 -0
  33. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/langchain_adapter.py +0 -0
  34. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/langgraph_workflow.py +0 -0
  35. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/model_switching.py +0 -0
  36. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/runtime_caps.py +0 -0
  37. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/examples/self_healing.py +0 -0
  38. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/governed.py +0 -0
  39. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/langchain_client.py +0 -0
  40. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/lifecycle.py +0 -0
  41. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/llm.py +0 -0
  42. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/policies.py +0 -0
  43. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/trace.py +0 -0
  44. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/ui/__init__.py +0 -0
  45. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/__init__.py +0 -0
  46. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/agent_policy_pb2.py +0 -0
  47. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/agent_policy_pb2_grpc.py +0 -0
  48. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/operation_pb2.py +0 -0
  49. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/operation_pb2_grpc.py +0 -0
  50. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/policy_pb2.py +0 -0
  51. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/policy_pb2_grpc.py +0 -0
  52. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/pricing_pb2.py +0 -0
  53. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/pricing_pb2_grpc.py +0 -0
  54. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/registration_pb2.py +0 -0
  55. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/registration_pb2_grpc.py +0 -0
  56. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/tenant_group_pb2.py +0 -0
  57. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/tenant_group_pb2_grpc.py +0 -0
  58. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/tenant_pb2.py +0 -0
  59. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/tenant_pb2_grpc.py +0 -0
  60. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/worker_pb2.py +0 -0
  61. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/worker_pb2_grpc.py +0 -0
  62. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/workflow_pb2.py +0 -0
  63. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/v1/workflow_pb2_grpc.py +0 -0
  64. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow/worker.py +0 -0
  65. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/SOURCES.txt +0 -0
  66. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/dependency_links.txt +0 -0
  67. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/entry_points.txt +0 -0
  68. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/requires.txt +0 -0
  69. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/boundflow.egg-info/top_level.txt +0 -0
  70. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/setup.cfg +0 -0
  71. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_agent_call_timeout.py +0 -0
  72. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_agent_lifecycle_policy.py +0 -0
  73. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_agent_metrics_latency.py +0 -0
  74. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_agent_policy_audit.py +0 -0
  75. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_approval_audit.py +0 -0
  76. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_approval_gate.py +0 -0
  77. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_await_input.py +0 -0
  78. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_capability_routing.py +0 -0
  79. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_complete_result.py +0 -0
  80. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_cooldown_and_resume.py +0 -0
  81. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_custom_runtime_policy.py +0 -0
  82. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_delayed_next.py +0 -0
  83. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_delete_tenant.py +0 -0
  84. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_delete_workflow.py +0 -0
  85. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_get_workflow.py +0 -0
  86. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_get_workflow_metrics.py +0 -0
  87. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_governed_model.py +0 -0
  88. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_governed_model_e2e.py +0 -0
  89. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_interim_metrics.py +0 -0
  90. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_invoke_context.py +0 -0
  91. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_invoke_mode.py +0 -0
  92. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_langchain_client.py +0 -0
  93. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_lifecycle_states.py +0 -0
  94. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_list_tenants.py +0 -0
  95. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_list_workflows.py +0 -0
  96. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_max_tokens_per_call.py +0 -0
  97. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_metrics_epoch_isolation.py +0 -0
  98. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_mock_llm.py +0 -0
  99. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_model_pricing.py +0 -0
  100. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_operation_context_ids.py +0 -0
  101. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_orchestrator_call_caps.py +0 -0
  102. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_orphaned_job_recovery.py +0 -0
  103. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_otel_sink.py +0 -0
  104. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_pending_approval.py +0 -0
  105. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_periodic_workflow.py +0 -0
  106. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_policy_audit.py +0 -0
  107. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_policy_getters.py +0 -0
  108. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_request_info.py +0 -0
  109. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_resolve_interrupted_workflow.py +0 -0
  110. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_resumable_workflow.py +0 -0
  111. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_run_agent_budget.py +0 -0
  112. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_run_agent_budget_e2e.py +0 -0
  113. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_set_workflow_config.py +0 -0
  114. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_suspend_parked_gate.py +0 -0
  115. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_suspend_resume.py +0 -0
  116. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_tenant_purge_reconciler.py +0 -0
  117. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_tool_call_limits.py +0 -0
  118. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_tool_failure_limits.py +0 -0
  119. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_trace.py +0 -0
  120. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_workflow_lifecycle_policy.py +0 -0
  121. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_workflow_purge_reconciler.py +0 -0
  122. {boundflow-0.6.0 → boundflow-0.7.0.dev7}/tests/test_workflow_runs.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boundflow
3
- Version: 0.6.0
3
+ Version: 0.7.0.dev7
4
4
  Summary: BoundFlow Python SDK — build governed fleets of agents against a self-hostable control plane.
5
5
  License-Expression: MIT
6
6
  Keywords: agents,llm,orchestration,control-plane,governance
@@ -83,6 +83,26 @@ def runtime_set(
83
83
  success(f"Runtime policy set on {workflow_id} / {agent_name}.")
84
84
 
85
85
 
86
+ @app.command("agents")
87
+ def list_agents(
88
+ workflow_id: str = typer.Argument(..., help="Workflow ID"),
89
+ ):
90
+ """List a workflow's agents and their armed policies.
91
+
92
+ Every other agent command needs a name; this is where the names come from.
93
+ """
94
+ agents = cp_call(lambda cp: cp.list_agents(workflow_id))
95
+ output([
96
+ {
97
+ "agent_name": a.agent_name,
98
+ "runtime_policy": a.runtime_policy or {},
99
+ "lifecycle_policy": a.lifecycle_policy or {},
100
+ "updated_at": a.updated_at,
101
+ }
102
+ for a in agents
103
+ ])
104
+
105
+
86
106
  @app.command("get-runtime")
87
107
  def runtime_get(
88
108
  workflow_id: str = typer.Argument(..., help="Workflow ID"),
@@ -364,6 +364,20 @@ class InputAuditRecord:
364
364
  prompt: str = ""
365
365
 
366
366
 
367
+ @dataclass
368
+ class Agent:
369
+ """One agent the server knows about, from `list_agents`.
370
+
371
+ A row exists once an agent has run or had a policy set, so an empty policy means
372
+ none is armed — not that the agent is unknown. Policies are dicts rather than
373
+ typed objects because the server stores them opaquely.
374
+ """
375
+ agent_name: str
376
+ runtime_policy: dict
377
+ lifecycle_policy: dict
378
+ updated_at: datetime | None
379
+
380
+
367
381
  @dataclass
368
382
  class PolicyActionRecord:
369
383
  """One workflow-lifecycle policy firing. Self-describing: the rule that fired
@@ -983,6 +997,25 @@ class ControlPlaneClient:
983
997
  metadata=self._metadata)
984
998
  return [_workflow_rule_from_proto(r) for r in resp.lifecycle_policy.rules]
985
999
 
1000
+ async def list_agents(self, workflow_id: str) -> list[Agent]:
1001
+ """Every agent the server knows about for a workflow, sorted by name.
1002
+
1003
+ The other agent getters all take an agent_name the caller is assumed to
1004
+ already know, which only works for whoever wrote the workflow. This is how
1005
+ anyone else discovers them.
1006
+ """
1007
+ resp = await self._lc.ListAgents(
1008
+ lc.ListAgentsRequest(workflow_id=workflow_id), metadata=self._metadata)
1009
+ return [
1010
+ Agent(
1011
+ agent_name=a.agent_name,
1012
+ runtime_policy=MessageToDict(a.runtime_policy),
1013
+ lifecycle_policy=MessageToDict(a.lifecycle_policy),
1014
+ updated_at=_ts(a, "updated_at"),
1015
+ )
1016
+ for a in resp.agents
1017
+ ]
1018
+
986
1019
  async def get_agent_runtime_policy(self, workflow_id: str, agent_name: str) -> dict:
987
1020
  """The armed runtime policy (hard caps + model override) for one agent, as a dict.
988
1021
  Empty dict if none is set."""
@@ -44,6 +44,7 @@ class Labels:
44
44
  deleted: str = "Deleted"
45
45
  metrics: str = "Metrics"
46
46
  audit: str = "Audit"
47
+ policies: str = "Policies"
47
48
  abandon: str = "Abandon queued runs"
48
49
  danger: str = "Delete"
49
50
 
@@ -52,6 +53,7 @@ class Labels:
52
53
  empty_fleet: str = "No workflows yet."
53
54
  empty_runs: str = "No runs yet."
54
55
  empty_holds: str = "Nothing is held."
56
+ empty_policies: str = "No policy armed."
55
57
  empty_deleted: str = "Nothing deleted."
56
58
 
57
59
 
@@ -140,7 +140,7 @@ a{color:inherit;text-decoration:none}
140
140
  .wrap{display:grid;grid-template-columns:190px 1fr;min-height:100vh}
141
141
  aside{background:var(--panel);border-right:1px solid var(--line);padding:14px 0;
142
142
  display:flex;flex-direction:column}
143
- aside .brand{padding:0 16px 14px;font-size:14px;font-weight:700;letter-spacing:.06em;
143
+ aside .brand{padding:0 16px 14px;font-size:15px;font-weight:700;letter-spacing:.06em;
144
144
  color:var(--acc);text-transform:uppercase}
145
145
  aside nav a{display:flex;justify-content:space-between;padding:6px 16px;color:var(--dim)}
146
146
  aside nav a:hover{background:var(--sel);color:var(--fg)}
@@ -152,15 +152,15 @@ aside .foot{margin-top:auto;padding:12px 16px 0;border-top:1px solid var(--line)
152
152
  main{display:flex;flex-direction:column;min-width:0}
153
153
  .bar{display:flex;align-items:center;gap:10px;padding:9px 16px;
154
154
  border-bottom:1px solid var(--line);background:var(--panel)}
155
- .bar .ctx{color:var(--acc);font-weight:600;white-space:nowrap}
155
+ .bar .ctx{color:var(--acc);font-weight:700;font-size:14px;white-space:nowrap}
156
156
  .bar input{flex:1;background:var(--bg);border:1px solid var(--line);border-radius:3px;
157
157
  color:var(--fg);font:inherit;padding:4px 8px;min-width:0}
158
158
  .bar input::placeholder{color:var(--dim)}
159
159
  .body{padding:14px 16px;overflow:auto;flex:1}
160
- h2{font-size:11px;text-transform:uppercase;letter-spacing:.12em;color:var(--dim);
161
- margin:18px 0 8px;font-weight:600}
160
+ h2{font-size:13px;text-transform:uppercase;letter-spacing:.1em;color:var(--fg);
161
+ margin:26px 0 10px;font-weight:700}
162
162
  h2:first-child{margin-top:0}
163
- h3{font-size:13px;margin:14px 0 4px;font-weight:600}
163
+ h3{font-size:13px;margin:16px 0 6px;font-weight:600}
164
164
  table{border-collapse:collapse;width:100%}
165
165
  th a{color:inherit}
166
166
  th a:hover{color:var(--acc)}
@@ -176,6 +176,12 @@ tbody tr.cur{background:var(--sel);box-shadow:inset 2px 0 0 var(--acc)}
176
176
  .pill.good{color:var(--good)}.pill.bad{color:var(--bad)}
177
177
  .pill.warn{color:var(--warn)}.pill.info{color:var(--info)}
178
178
  .muted,.dim{color:var(--dim)}
179
+ .chip{display:inline-block;padding:1px 7px;margin:1px 3px 1px 0;border-radius:2px;
180
+ background:var(--sel);border:1px solid var(--line);font-size:11px;white-space:nowrap}
181
+ .act{color:var(--acc);font-weight:600}
182
+ strong.sub{display:block;font-size:11px;text-transform:uppercase;letter-spacing:.1em;
183
+ color:var(--fg);margin-bottom:9px;font-weight:700}
184
+ .card td{white-space:normal}
179
185
  .card{background:var(--panel);border:1px solid var(--line);
180
186
  border-left:2px solid var(--warn);padding:12px 14px;margin-bottom:10px}
181
187
  dl{display:grid;grid-template-columns:minmax(110px,auto) 1fr;gap:3px 18px;margin:0}
@@ -248,21 +248,26 @@ def build_app(console: Console):
248
248
  return failed(request, console.labels.workflow.capitalize(), exc)
249
249
  # Every panel is optional: a workflow with a broken metrics read still has
250
250
  # to render, because the page is how an operator finds out what is wrong.
251
- runs, metrics, audit, policies = await asyncio.gather(
251
+ runs, metrics, audit, policies, wf_policy, agents = await asyncio.gather(
252
252
  console.cp.list_workflow_runs(wid),
253
253
  console.cp.get_workflow_metrics(wid),
254
254
  console.cp.get_audit_log(wid),
255
255
  console.cp.get_workflow_policy_audit(wid),
256
+ console.cp.get_workflow_lifecycle_policy(wid),
257
+ console.cp.list_agents(wid),
256
258
  return_exceptions=True,
257
259
  )
258
260
  for name, value in (("runs", runs), ("metrics", metrics),
259
- ("audit", audit), ("policy audit", policies)):
261
+ ("audit", audit), ("policy audit", policies),
262
+ ("lifecycle policy", wf_policy), ("agents", agents)):
260
263
  if isinstance(value, BaseException):
261
264
  log.warning("could not load %s for %s", name, wid, exc_info=value)
262
265
  runs = [] if isinstance(runs, BaseException) else runs
263
266
  metrics = None if isinstance(metrics, BaseException) else metrics
264
267
  audit = [] if isinstance(audit, BaseException) else audit
265
268
  policies = [] if isinstance(policies, BaseException) else policies
269
+ wf_policy = [] if isinstance(wf_policy, BaseException) else wf_policy
270
+ agents = [] if isinstance(agents, BaseException) else agents
266
271
 
267
272
  # The decision that put the workflow in its current state, so the callout can
268
273
  # say what crossed rather than only that something did.
@@ -270,7 +275,8 @@ def build_app(console: Console):
270
275
  (p for p in policies
271
276
  if p.request_id == workflow.last_policy_decision_request_id), None)
272
277
  return render(wid, views.workflow_detail(workflow, runs, metrics,
273
- console.labels, audit, decision),
278
+ console.labels, audit, decision,
279
+ wf_policy, agents),
274
280
  request, current="", filterable=False)
275
281
 
276
282
  async def act(request, fn):
@@ -519,9 +519,144 @@ def audit_table(records: list[Any], lb: Labels = DEFAULT) -> str:
519
519
  empty="Nothing recorded yet.")
520
520
 
521
521
 
522
+ def _duration(seconds: int) -> str:
523
+ if seconds % 3600 == 0 and seconds >= 3600:
524
+ return f"{seconds // 3600}h"
525
+ if seconds % 60 == 0 and seconds >= 60:
526
+ return f"{seconds // 60}m"
527
+ return f"{seconds}s"
528
+
529
+
530
+ def _threshold(metric: str, value: Any) -> str:
531
+ """Thresholds are bare numbers on the wire; a cost of 5 and a count of 5 read the
532
+ same without their unit."""
533
+ metric = fmt(metric)
534
+ if metric == "cost":
535
+ return f"${float(value):,.2f}"
536
+ if metric == "latency":
537
+ return _duration(int(float(value)))
538
+ if metric == "tool_failure_rate":
539
+ return f"{float(value) * 100:g}%"
540
+ return fmt(value)
541
+
542
+
543
+ def _action(action: Any) -> str:
544
+ """A workflow policy action, in words. The window is a column of its own, so it
545
+ isn't repeated here.
546
+
547
+ These are dataclasses, so letting them fall through to str() put a Python repr —
548
+ `kind='cooldown' window=10 seconds=1800` — on the page.
549
+ """
550
+ kind = fmt(getattr(action, "kind", action))
551
+ if kind == "cooldown":
552
+ return f"cool down {_duration(getattr(action, 'seconds', 0))}"
553
+ if kind == "pause":
554
+ return "pause"
555
+ if kind == "set_version":
556
+ return f"roll back to version {fmt(getattr(action, 'target', ''))}"
557
+ return kind
558
+
559
+
560
+ def _window(n: Any) -> str:
561
+ n = int(n or 0)
562
+ if not n:
563
+ return "—"
564
+ return f"{n} run" if n == 1 else f"{n} runs"
565
+
566
+
567
+ def _agent_rule_rows(agents: list[Any]) -> list[list[str]]:
568
+ """Agent adaptive rules, one row each, in the same columns as the workflow rules.
569
+
570
+ These arrive as plain dicts, since the server stores the policy opaquely.
571
+ """
572
+ rows = []
573
+ for a in agents:
574
+ for r in (a.lifecycle_policy or {}).get("rules") or []:
575
+ metric = fmt(r.get("metric"))
576
+ action = r.get("action") or {}
577
+ target = (f"{fmt(action.get('field'))} = {fmt(action.get('value'))}"
578
+ if isinstance(action, dict) else fmt(action))
579
+ rows.append([
580
+ f'<span class="mono">{esc(a.agent_name)}</span>',
581
+ f'<span class="chip">{esc(metric)}</span>',
582
+ f'{esc(fmt(r.get("op") or "≥"))} '
583
+ f'{esc(_threshold(metric.replace("_usd", ""), r.get("threshold", 0)))}',
584
+ esc(_window(r.get("window"))),
585
+ f'<span class="act">{esc(target)}</span>',
586
+ ])
587
+ return rows
588
+
589
+
590
+ def _chips(policy: dict) -> str:
591
+ """An agent's caps as chips rather than a run-on of key: value pairs."""
592
+ if not policy:
593
+ return '<span class="muted">none armed</span>'
594
+ out = []
595
+ for k, v in sorted(policy.items()):
596
+ if v in (0, 0.0, "", None, [], {}):
597
+ continue # unset fields come back as zeroes, not absences
598
+ label = str(k).replace("_", " ")
599
+ if k == "max_cost_usd":
600
+ text = f"cost ≤ ${float(v):,.2f}"
601
+ elif k == "model":
602
+ text = fmt(v)
603
+ elif isinstance(v, (list, dict)):
604
+ text = f"{label} ({len(v)})"
605
+ else:
606
+ text = f"{label} {fmt(v)}"
607
+ out.append(f'<span class="chip">{esc(text)}</span>')
608
+ return " ".join(out) or '<span class="muted">none armed</span>'
609
+
610
+
611
+ def policies_section(workflow_policy: Any, agents: list[Any],
612
+ lb: Labels = DEFAULT) -> str:
613
+ """What is actually armed on this workflow and its agents.
614
+
615
+ The console could say a lifecycle policy had paused a workflow without ever
616
+ showing the rule that did it. Agents are listed even when nothing is armed,
617
+ because "this agent has no caps" is itself worth seeing on a governance screen —
618
+ and it's the row you'd most want to catch.
619
+ """
620
+ rules = workflow_policy or []
621
+ if rules:
622
+ wf_rows = [
623
+ [f'<span class="chip">{esc(fmt(getattr(r, "metric", "")))}</span>',
624
+ f'≥ {_threshold(getattr(r, "metric", ""), getattr(r, "threshold", 0))}',
625
+ esc(_window(getattr(getattr(r, "action", None), "window", 0))),
626
+ esc(getattr(r, "tool", "") or "—"),
627
+ f'<span class="act">{esc(_action(getattr(r, "action", None)))}</span>']
628
+ for r in rules
629
+ ]
630
+ wf = table(["when", "crosses", "over", "tool", "then"], wf_rows)
631
+ else:
632
+ wf = f'<p class="muted">{esc(lb.empty_policies)}</p>'
633
+
634
+ if agents:
635
+ caps = table(
636
+ ["agent", "caps", "updated"],
637
+ [[f'<span class="mono">{esc(a.agent_name)}</span>',
638
+ _chips(a.runtime_policy), esc(a.updated_at)] for a in agents],
639
+ )
640
+ rule_rows = _agent_rule_rows(agents)
641
+ rules_tbl = table(["agent", "when", "crosses", "over", "then"], rule_rows,
642
+ empty="No adaptive rules armed.")
643
+ else:
644
+ caps = '<p class="muted">No agents have run yet.</p>'
645
+ rules_tbl = caps
646
+
647
+ return (
648
+ f"<h2>{esc(lb.policies)}</h2>"
649
+ f'<div class="card"><strong class="sub">Workflow lifecycle</strong>{wf}</div>'
650
+ f'<div class="card"><strong class="sub">Agent runtime caps</strong>{caps}</div>'
651
+ f'<div class="card"><strong class="sub">Agent lifecycle rules</strong>'
652
+ f'{rules_tbl}</div>'
653
+ )
654
+
655
+
522
656
  def workflow_detail(w: WorkflowInfo, runs: list[Any], metrics: Any,
523
657
  lb: Labels = DEFAULT, audit: list[Any] | None = None,
524
- policy: Any = None) -> str:
658
+ policy: Any = None, workflow_policy: Any = None,
659
+ agents: list[Any] | None = None) -> str:
525
660
  gates = approval_form(w) + input_form(w)
526
661
  gates_section = f"<h2>{esc(lb.inbox)}</h2>{gates}" if gates else ""
527
662
  return (
@@ -531,6 +666,7 @@ def workflow_detail(w: WorkflowInfo, runs: list[Any], metrics: Any,
531
666
  f"{status_callout(w, lb, policy)}"
532
667
  f"{gates_section}"
533
668
  f'<div class="card">{detail_rows(w, skip=("pending_approval", "pending_input"))}</div>'
669
+ f"{policies_section(workflow_policy, agents or [], lb)}"
534
670
  f"<h2>{esc(lb.metrics)} (version {esc(w.version)})</h2>"
535
671
  f"{metrics_cards(metrics, lb)}"
536
672
  f"<h2>{esc(lb.runs).capitalize()}</h2>{runs_table(runs, lb)}"
@@ -0,0 +1,201 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # NO CHECKED-IN PROTOBUF GENCODE
4
+ # source: boundflow/v1/lifecycle.proto
5
+ # Protobuf Python Version: 6.33.5
6
+ """Generated protocol buffer code."""
7
+ from google.protobuf import descriptor as _descriptor
8
+ from google.protobuf import descriptor_pool as _descriptor_pool
9
+ from google.protobuf import runtime_version as _runtime_version
10
+ from google.protobuf import symbol_database as _symbol_database
11
+ from google.protobuf.internal import builder as _builder
12
+ _runtime_version.ValidateProtobufRuntimeVersion(
13
+ _runtime_version.Domain.PUBLIC,
14
+ 6,
15
+ 33,
16
+ 5,
17
+ '',
18
+ 'boundflow/v1/lifecycle.proto'
19
+ )
20
+ # @@protoc_insertion_point(imports)
21
+
22
+ _sym_db = _symbol_database.Default()
23
+
24
+
25
+ from google.protobuf import struct_pb2 as google_dot_protobuf_dot_struct__pb2
26
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
27
+ from boundflow.v1 import workflow_pb2 as boundflow_dot_v1_dot_workflow__pb2
28
+ from boundflow.v1 import agent_policy_pb2 as boundflow_dot_v1_dot_agent__policy__pb2
29
+
30
+
31
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x62oundflow/v1/lifecycle.proto\x12\x0c\x62oundflow.v1\x1a\x1cgoogle/protobuf/struct.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x1b\x62oundflow/v1/workflow.proto\x1a\x1f\x62oundflow/v1/agent_policy.proto\"\xb9\x01\n\x15\x43reateWorkflowRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x15\n\rworkflow_type\x18\x02 \x01(\t\x12\x11\n\ttenant_id\x18\x03 \x01(\t\x12!\n\x19operation_timeout_seconds\x18\x05 \x01(\x05\x12\x35\n\x0fworkflow_config\x18\x06 \x01(\x0b\x32\x1c.boundflow.v1.WorkflowConfigJ\x04\x08\x04\x10\x05\"B\n\x16\x43reateWorkflowResponse\x12(\n\x08workflow\x18\x01 \x01(\x0b\x32\x16.boundflow.v1.Workflow\"\x16\n\x14ListWorkflowsRequest\"B\n\x15ListWorkflowsResponse\x12)\n\tworkflows\x18\x01 \x03(\x0b\x32\x16.boundflow.v1.Workflow\"5\n\x10RuntimeOverrides\x12!\n\x19operation_timeout_seconds\x18\x02 \x01(\x05\"\xb1\x01\n\x15InvokeWorkflowRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x39\n\x11runtime_overrides\x18\x03 \x01(\x0b\x32\x1e.boundflow.v1.RuntimeOverrides\x12\x30\n\x0finitial_context\x18\x04 \x01(\x0b\x32\x17.google.protobuf.Struct\",\n\x16InvokeWorkflowResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\"\x86\x01\n\x16SuspendWorkflowRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x0e\n\x06reason\x18\x03 \x01(\t\x12\x18\n\x10stop_current_run\x18\x04 \x01(\x08\x12\x15\n\rsuspension_id\x18\x06 \x01(\t\"0\n\x17SuspendWorkflowResponse\x12\x15\n\rsuspension_id\x18\x01 \x01(\t\"m\n\x1c\x41\x62\x61ndonQueuedRequestsRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x13\n\x0brequest_ids\x18\x03 \x03(\t\x12\x0b\n\x03\x61ll\x18\x04 \x01(\x08\"4\n\x1d\x41\x62\x61ndonQueuedRequestsResponse\x12\x13\n\x0brequest_ids\x18\x01 \x03(\t\"[\n\x15ResumeWorkflowRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x15\n\rsuspension_id\x18\x03 \x01(\t\"\x18\n\x16ResumeWorkflowResponse\"g\n\x15\x44\x65leteWorkflowRequest\x12\x16\n\x0e\x63orrelation_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12!\n\x19operation_timeout_seconds\x18\x03 \x01(\x05\",\n\x16\x44\x65leteWorkflowResponse\x12\x12\n\nrequest_id\x18\x01 \x01(\t\")\n\x12GetWorkflowRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"?\n\x13GetWorkflowResponse\x12(\n\x08workflow\x18\x01 \x01(\x0b\x32\x16.boundflow.v1.Workflow\"x\n\x1cSetAgentRuntimePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\x12/\n\x0eruntime_policy\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\"\x1f\n\x1dSetAgentRuntimePolicyResponse\"|\n\x1eSetAgentLifecyclePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\x12\x31\n\x10lifecycle_policy\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\"!\n\x1fSetAgentLifecyclePolicyResponse\"=\n\x12\x44\x65leteAgentRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\"\x15\n\x13\x44\x65leteAgentResponse\"\x87\x01\n\x1dWorkflowLifecyclePolicyAction\x12\x34\n\x04type\x18\x01 \x01(\x0e\x32&.boundflow.v1.WorkflowPolicyActionType\x12\x18\n\x10\x63ooldown_seconds\x18\x02 \x01(\x05\x12\x16\n\x0etarget_version\x18\x03 \x01(\x05\"\xbe\x01\n\x1bWorkflowLifecyclePolicyRule\x12,\n\x06metric\x18\x01 \x01(\x0e\x32\x1c.boundflow.v1.WorkflowMetric\x12\x11\n\tthreshold\x18\x02 \x01(\x01\x12\x0e\n\x06window\x18\x03 \x01(\x05\x12\x11\n\ttool_name\x18\x04 \x01(\t\x12;\n\x06\x61\x63tion\x18\x05 \x01(\x0b\x32+.boundflow.v1.WorkflowLifecyclePolicyAction\"S\n\x17WorkflowLifecyclePolicy\x12\x38\n\x05rules\x18\x01 \x03(\x0b\x32).boundflow.v1.WorkflowLifecyclePolicyRule\"y\n!SetWorkflowLifecyclePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12?\n\x10lifecycle_policy\x18\x02 \x01(\x0b\x32%.boundflow.v1.WorkflowLifecyclePolicy\"$\n\"SetWorkflowLifecyclePolicyResponse\"8\n!GetWorkflowLifecyclePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"e\n\"GetWorkflowLifecyclePolicyResponse\x12?\n\x10lifecycle_policy\x18\x01 \x01(\x0b\x32%.boundflow.v1.WorkflowLifecyclePolicy\"(\n\x11ListAgentsRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"9\n\x12ListAgentsResponse\x12#\n\x06\x61gents\x18\x01 \x03(\x0b\x32\x13.boundflow.v1.Agent\"\xaf\x01\n\x05\x41gent\x12\x12\n\nagent_name\x18\x01 \x01(\t\x12/\n\x0eruntime_policy\x18\x02 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x31\n\x10lifecycle_policy\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\x12.\n\nupdated_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\"G\n\x1cGetAgentRuntimePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\"P\n\x1dGetAgentRuntimePolicyResponse\x12/\n\x0eruntime_policy\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\"I\n\x1eGetAgentLifecyclePolicyRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\"T\n\x1fGetAgentLifecyclePolicyResponse\x12\x31\n\x10lifecycle_policy\x18\x01 \x01(\x0b\x32\x17.google.protobuf.Struct\"a\n\x16\x41pproveWorkflowRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x13\n\x0b\x61pproval_id\x18\x02 \x01(\t\x12\r\n\x05\x61\x63tor\x18\x03 \x01(\t\x12\x0e\n\x06reason\x18\x04 \x01(\t\"\x19\n\x17\x41pproveWorkflowResponse\"`\n\x15RejectWorkflowRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x13\n\x0b\x61pproval_id\x18\x02 \x01(\t\x12\r\n\x05\x61\x63tor\x18\x03 \x01(\t\x12\x0e\n\x06reason\x18\x04 \x01(\t\"s\n\x12SubmitInputRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x10\n\x08input_id\x18\x02 \x01(\t\x12\'\n\x06\x61nswer\x18\x03 \x01(\x0b\x32\x17.google.protobuf.Struct\x12\r\n\x05\x61\x63tor\x18\x04 \x01(\t\"\x15\n\x13SubmitInputResponse\".\n\x17GetApprovalAuditRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"N\n\x18GetApprovalAuditResponse\x12\x32\n\x07records\x18\x01 \x03(\x0b\x32!.boundflow.v1.ApprovalAuditRecord\"2\n\x1bGetApprovalAuditByIdRequest\x12\x13\n\x0b\x61pproval_id\x18\x01 \x01(\t\"Q\n\x1cGetApprovalAuditByIdResponse\x12\x31\n\x06record\x18\x01 \x01(\x0b\x32!.boundflow.v1.ApprovalAuditRecord\"+\n\x14GetInputAuditRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"H\n\x15GetInputAuditResponse\x12/\n\x07records\x18\x01 \x03(\x0b\x32\x1e.boundflow.v1.InputAuditRecord\"4\n\x1dGetWorkflowPolicyAuditRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"Z\n\x1eGetWorkflowPolicyAuditResponse\x12\x38\n\x07records\x18\x01 \x03(\x0b\x32\'.boundflow.v1.WorkflowPolicyAuditRecord\"E\n\x1aGetAgentPolicyAuditRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nagent_name\x18\x02 \x01(\t\"T\n\x1bGetAgentPolicyAuditResponse\x12\x35\n\x07records\x18\x01 \x03(\x0b\x32$.boundflow.v1.AgentPolicyAuditRecord\")\n\x12GetAuditLogRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"@\n\x13GetAuditLogResponse\x12)\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x18.boundflow.v1.AuditEntry\"\xff\x01\n\nAuditEntry\x12\x35\n\x08\x61pproval\x18\x01 \x01(\x0b\x32!.boundflow.v1.ApprovalAuditRecordH\x00\x12\x42\n\x0fworkflow_policy\x18\x02 \x01(\x0b\x32\'.boundflow.v1.WorkflowPolicyAuditRecordH\x00\x12<\n\x0c\x61gent_policy\x18\x03 \x01(\x0b\x32$.boundflow.v1.AgentPolicyAuditRecordH\x00\x12/\n\x05input\x18\x04 \x01(\x0b\x32\x1e.boundflow.v1.InputAuditRecordH\x00\x42\x07\n\x05\x65ntry\"\xcb\x02\n\x13\x41pprovalAuditRecord\x12\x13\n\x0b\x61pproval_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12\x30\n\x08\x64\x65\x63ision\x18\x04 \x01(\x0e\x32\x1e.boundflow.v1.ApprovalDecision\x12-\n\topened_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\ndecided_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05\x61\x63tor\x18\x07 \x01(\t\x12/\n\x0boccurred_at\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x15\n\rjustification\x18\t \x01(\t\x12\x0e\n\x06reason\x18\n \x01(\t\"\xd4\x02\n\x10InputAuditRecord\x12\x10\n\x08input_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x12\n\nrequest_id\x18\x03 \x01(\t\x12-\n\x08\x64\x65\x63ision\x18\x04 \x01(\x0e\x32\x1b.boundflow.v1.InputDecision\x12-\n\topened_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12.\n\ndecided_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\r\n\x05\x61\x63tor\x18\x07 \x01(\t\x12/\n\x0boccurred_at\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x06\x61nswer\x18\t \x01(\x0b\x32\x17.google.protobuf.Struct\x12\x0e\n\x06prompt\x18\n \x01(\t\"\x86\x02\n\x19WorkflowPolicyAuditRecord\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nrequest_id\x18\x02 \x01(\t\x12\r\n\x05\x61\x63tor\x18\x03 \x01(\t\x12/\n\x0boccurred_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x37\n\x04rule\x18\x05 \x01(\x0b\x32).boundflow.v1.WorkflowLifecyclePolicyRule\x12\x15\n\rtrigger_value\x18\x06 \x01(\x01\x12\x18\n\x10previous_version\x18\x07 \x01(\x05\x12\x16\n\x0eprevious_state\x18\x08 \x01(\t\"\xc6\x01\n\x16\x41gentPolicyAuditRecord\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nrequest_id\x18\x02 \x01(\t\x12\r\n\x05\x61\x63tor\x18\x03 \x01(\t\x12/\n\x0boccurred_at\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x12\n\nagent_name\x18\x05 \x01(\t\x12/\n\x06\x61\x63tion\x18\x06 \x01(\x0b\x32\x1f.boundflow.v1.AgentPolicyAction\"\x18\n\x16RejectWorkflowResponse\"B\n\x17\x41\x63tivateWorkflowRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nrequest_id\x18\x02 \x01(\t\"\x1a\n\x18\x41\x63tivateWorkflowResponse\"L\n!ResolveInterruptedWorkflowRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12\x12\n\nrequest_id\x18\x02 \x01(\t\"$\n\"ResolveInterruptedWorkflowResponse\".\n\x17ListWorkflowRunsRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"\xce\x01\n\x03Run\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x14\n\x0crequest_type\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x07 \x01(\t\x12\x13\n\x0brun_outcome\x18\x03 \x01(\t\x12\x16\n\x0e\x66\x61ilure_reason\x18\x04 \x01(\t\x12.\n\ncreated_at\x18\x05 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0c\x63ompleted_at\x18\x06 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\";\n\x18ListWorkflowRunsResponse\x12\x1f\n\x04runs\x18\x01 \x03(\x0b\x32\x11.boundflow.v1.Run\"+\n\x15GetRequestInfoRequest\x12\x12\n\nrequest_id\x18\x01 \x01(\t\"\xb2\x03\n\x0bRequestInfo\x12\x12\n\nrequest_id\x18\x01 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x02 \x01(\t\x12\x14\n\x0crequest_type\x18\x03 \x01(\t\x12\x0e\n\x06status\x18\x04 \x01(\t\x12\x13\n\x0brun_outcome\x18\x05 \x01(\t\x12\x16\n\x0e\x66\x61ilure_reason\x18\x06 \x01(\t\x12\x0f\n\x07version\x18\x07 \x01(\x03\x12.\n\ncreated_at\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x30\n\x0c\x63ompleted_at\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\'\n\x06result\x18\n \x01(\x0b\x32\x17.google.protobuf.Struct\x12/\n\x0einvoke_context\x18\x0b \x01(\x0b\x32\x17.google.protobuf.Struct\x12!\n\x19operation_timeout_seconds\x18\x0c \x01(\x05\x12\x37\n\x16\x61gent_runtime_policies\x18\r \x01(\x0b\x32\x17.google.protobuf.Struct\"D\n\x16GetRequestInfoResponse\x12*\n\x07request\x18\x01 \x01(\x0b\x32\x19.boundflow.v1.RequestInfo\"0\n\x19GetWorkflowMetricsRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\"\xdf\x02\n\x1aGetWorkflowMetricsResponse\x12\x0f\n\x07version\x18\x01 \x01(\x05\x12\x12\n\ntotal_cost\x18\x02 \x01(\x01\x12\x11\n\trun_count\x18\x03 \x01(\x05\x12\x16\n\x0etotal_failures\x18\x04 \x01(\x05\x12\x17\n\x0ftotal_llm_calls\x18\x05 \x01(\x05\x12\x1d\n\x15total_latency_seconds\x18\x06 \x01(\x01\x12!\n\x19total_approval_rejections\x18\x07 \x01(\x05\x12\\\n\x13tool_failure_counts\x18\x08 \x03(\x0b\x32?.boundflow.v1.GetWorkflowMetricsResponse.ToolFailureCountsEntry\x1a\x38\n\x16ToolFailureCountsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"]\n\x18SetWorkflowConfigRequest\x12\x13\n\x0bworkflow_id\x18\x01 \x01(\t\x12,\n\x06\x63onfig\x18\x02 \x01(\x0b\x32\x1c.boundflow.v1.WorkflowConfig\"E\n\x19SetWorkflowConfigResponse\x12(\n\x08workflow\x18\x01 \x01(\x0b\x32\x16.boundflow.v1.Workflow*\xdc\x01\n\x0eWorkflowMetric\x12 \n\x1cWORKFLOW_METRIC_NUM_FAILURES\x10\x00\x12\x18\n\x14WORKFLOW_METRIC_COST\x10\x01\x12!\n\x1dWORKFLOW_METRIC_NUM_LLM_CALLS\x10\x02\x12\x1b\n\x17WORKFLOW_METRIC_LATENCY\x10\x03\x12\'\n#WORKFLOW_METRIC_APPROVAL_REJECTIONS\x10\x04\x12%\n!WORKFLOW_METRIC_TOOL_FAILURE_RATE\x10\x05*\x89\x01\n\x18WorkflowPolicyActionType\x12 \n\x1cWORKFLOW_POLICY_ACTION_PAUSE\x10\x00\x12#\n\x1fWORKFLOW_POLICY_ACTION_COOLDOWN\x10\x01\x12&\n\"WORKFLOW_POLICY_ACTION_SET_VERSION\x10\x02*\x96\x01\n\x10\x41pprovalDecision\x12!\n\x1d\x41PPROVAL_DECISION_UNSPECIFIED\x10\x00\x12\x1e\n\x1a\x41PPROVAL_DECISION_APPROVED\x10\x01\x12\x1e\n\x1a\x41PPROVAL_DECISION_REJECTED\x10\x02\x12\x1f\n\x1b\x41PPROVAL_DECISION_TIMED_OUT\x10\x03*j\n\rInputDecision\x12\x1e\n\x1aINPUT_DECISION_UNSPECIFIED\x10\x00\x12\x1b\n\x17INPUT_DECISION_ANSWERED\x10\x01\x12\x1c\n\x18INPUT_DECISION_TIMED_OUT\x10\x02\x32\xe5\x18\n\x0fWorkflowService\x12[\n\x0e\x43reateWorkflow\x12#.boundflow.v1.CreateWorkflowRequest\x1a$.boundflow.v1.CreateWorkflowResponse\x12[\n\x0eInvokeWorkflow\x12#.boundflow.v1.InvokeWorkflowRequest\x1a$.boundflow.v1.InvokeWorkflowResponse\x12[\n\x0e\x44\x65leteWorkflow\x12#.boundflow.v1.DeleteWorkflowRequest\x1a$.boundflow.v1.DeleteWorkflowResponse\x12^\n\x0fSuspendWorkflow\x12$.boundflow.v1.SuspendWorkflowRequest\x1a%.boundflow.v1.SuspendWorkflowResponse\x12[\n\x0eResumeWorkflow\x12#.boundflow.v1.ResumeWorkflowRequest\x1a$.boundflow.v1.ResumeWorkflowResponse\x12p\n\x15\x41\x62\x61ndonQueuedRequests\x12*.boundflow.v1.AbandonQueuedRequestsRequest\x1a+.boundflow.v1.AbandonQueuedRequestsResponse\x12R\n\x0bGetWorkflow\x12 .boundflow.v1.GetWorkflowRequest\x1a!.boundflow.v1.GetWorkflowResponse\x12X\n\rListWorkflows\x12\".boundflow.v1.ListWorkflowsRequest\x1a#.boundflow.v1.ListWorkflowsResponse\x12p\n\x15SetAgentRuntimePolicy\x12*.boundflow.v1.SetAgentRuntimePolicyRequest\x1a+.boundflow.v1.SetAgentRuntimePolicyResponse\x12v\n\x17SetAgentLifecyclePolicy\x12,.boundflow.v1.SetAgentLifecyclePolicyRequest\x1a-.boundflow.v1.SetAgentLifecyclePolicyResponse\x12R\n\x0b\x44\x65leteAgent\x12 .boundflow.v1.DeleteAgentRequest\x1a!.boundflow.v1.DeleteAgentResponse\x12\x7f\n\x1aSetWorkflowLifecyclePolicy\x12/.boundflow.v1.SetWorkflowLifecyclePolicyRequest\x1a\x30.boundflow.v1.SetWorkflowLifecyclePolicyResponse\x12\x7f\n\x1aGetWorkflowLifecyclePolicy\x12/.boundflow.v1.GetWorkflowLifecyclePolicyRequest\x1a\x30.boundflow.v1.GetWorkflowLifecyclePolicyResponse\x12p\n\x15GetAgentRuntimePolicy\x12*.boundflow.v1.GetAgentRuntimePolicyRequest\x1a+.boundflow.v1.GetAgentRuntimePolicyResponse\x12v\n\x17GetAgentLifecyclePolicy\x12,.boundflow.v1.GetAgentLifecyclePolicyRequest\x1a-.boundflow.v1.GetAgentLifecyclePolicyResponse\x12O\n\nListAgents\x12\x1f.boundflow.v1.ListAgentsRequest\x1a .boundflow.v1.ListAgentsResponse\x12^\n\x0f\x41pproveWorkflow\x12$.boundflow.v1.ApproveWorkflowRequest\x1a%.boundflow.v1.ApproveWorkflowResponse\x12[\n\x0eRejectWorkflow\x12#.boundflow.v1.RejectWorkflowRequest\x1a$.boundflow.v1.RejectWorkflowResponse\x12R\n\x0bSubmitInput\x12 .boundflow.v1.SubmitInputRequest\x1a!.boundflow.v1.SubmitInputResponse\x12\x61\n\x10GetApprovalAudit\x12%.boundflow.v1.GetApprovalAuditRequest\x1a&.boundflow.v1.GetApprovalAuditResponse\x12m\n\x14GetApprovalAuditById\x12).boundflow.v1.GetApprovalAuditByIdRequest\x1a*.boundflow.v1.GetApprovalAuditByIdResponse\x12X\n\rGetInputAudit\x12\".boundflow.v1.GetInputAuditRequest\x1a#.boundflow.v1.GetInputAuditResponse\x12s\n\x16GetWorkflowPolicyAudit\x12+.boundflow.v1.GetWorkflowPolicyAuditRequest\x1a,.boundflow.v1.GetWorkflowPolicyAuditResponse\x12j\n\x13GetAgentPolicyAudit\x12(.boundflow.v1.GetAgentPolicyAuditRequest\x1a).boundflow.v1.GetAgentPolicyAuditResponse\x12R\n\x0bGetAuditLog\x12 .boundflow.v1.GetAuditLogRequest\x1a!.boundflow.v1.GetAuditLogResponse\x12\x61\n\x10\x41\x63tivateWorkflow\x12%.boundflow.v1.ActivateWorkflowRequest\x1a&.boundflow.v1.ActivateWorkflowResponse\x12\x7f\n\x1aResolveInterruptedWorkflow\x12/.boundflow.v1.ResolveInterruptedWorkflowRequest\x1a\x30.boundflow.v1.ResolveInterruptedWorkflowResponse\x12\x61\n\x10ListWorkflowRuns\x12%.boundflow.v1.ListWorkflowRunsRequest\x1a&.boundflow.v1.ListWorkflowRunsResponse\x12[\n\x0eGetRequestInfo\x12#.boundflow.v1.GetRequestInfoRequest\x1a$.boundflow.v1.GetRequestInfoResponse\x12g\n\x12GetWorkflowMetrics\x12\'.boundflow.v1.GetWorkflowMetricsRequest\x1a(.boundflow.v1.GetWorkflowMetricsResponse\x12\x64\n\x11SetWorkflowConfig\x12&.boundflow.v1.SetWorkflowConfigRequest\x1a\'.boundflow.v1.SetWorkflowConfigResponseB=Z;github.com/boundflow/boundflow/gen/boundflow/v1;boundflowv1b\x06proto3')
32
+
33
+ _globals = globals()
34
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
35
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'boundflow.v1.lifecycle_pb2', _globals)
36
+ if not _descriptor._USE_C_DESCRIPTORS:
37
+ _globals['DESCRIPTOR']._loaded_options = None
38
+ _globals['DESCRIPTOR']._serialized_options = b'Z;github.com/boundflow/boundflow/gen/boundflow/v1;boundflowv1'
39
+ _globals['_GETWORKFLOWMETRICSRESPONSE_TOOLFAILURECOUNTSENTRY']._loaded_options = None
40
+ _globals['_GETWORKFLOWMETRICSRESPONSE_TOOLFAILURECOUNTSENTRY']._serialized_options = b'8\001'
41
+ _globals['_WORKFLOWMETRIC']._serialized_start=7503
42
+ _globals['_WORKFLOWMETRIC']._serialized_end=7723
43
+ _globals['_WORKFLOWPOLICYACTIONTYPE']._serialized_start=7726
44
+ _globals['_WORKFLOWPOLICYACTIONTYPE']._serialized_end=7863
45
+ _globals['_APPROVALDECISION']._serialized_start=7866
46
+ _globals['_APPROVALDECISION']._serialized_end=8016
47
+ _globals['_INPUTDECISION']._serialized_start=8018
48
+ _globals['_INPUTDECISION']._serialized_end=8124
49
+ _globals['_CREATEWORKFLOWREQUEST']._serialized_start=172
50
+ _globals['_CREATEWORKFLOWREQUEST']._serialized_end=357
51
+ _globals['_CREATEWORKFLOWRESPONSE']._serialized_start=359
52
+ _globals['_CREATEWORKFLOWRESPONSE']._serialized_end=425
53
+ _globals['_LISTWORKFLOWSREQUEST']._serialized_start=427
54
+ _globals['_LISTWORKFLOWSREQUEST']._serialized_end=449
55
+ _globals['_LISTWORKFLOWSRESPONSE']._serialized_start=451
56
+ _globals['_LISTWORKFLOWSRESPONSE']._serialized_end=517
57
+ _globals['_RUNTIMEOVERRIDES']._serialized_start=519
58
+ _globals['_RUNTIMEOVERRIDES']._serialized_end=572
59
+ _globals['_INVOKEWORKFLOWREQUEST']._serialized_start=575
60
+ _globals['_INVOKEWORKFLOWREQUEST']._serialized_end=752
61
+ _globals['_INVOKEWORKFLOWRESPONSE']._serialized_start=754
62
+ _globals['_INVOKEWORKFLOWRESPONSE']._serialized_end=798
63
+ _globals['_SUSPENDWORKFLOWREQUEST']._serialized_start=801
64
+ _globals['_SUSPENDWORKFLOWREQUEST']._serialized_end=935
65
+ _globals['_SUSPENDWORKFLOWRESPONSE']._serialized_start=937
66
+ _globals['_SUSPENDWORKFLOWRESPONSE']._serialized_end=985
67
+ _globals['_ABANDONQUEUEDREQUESTSREQUEST']._serialized_start=987
68
+ _globals['_ABANDONQUEUEDREQUESTSREQUEST']._serialized_end=1096
69
+ _globals['_ABANDONQUEUEDREQUESTSRESPONSE']._serialized_start=1098
70
+ _globals['_ABANDONQUEUEDREQUESTSRESPONSE']._serialized_end=1150
71
+ _globals['_RESUMEWORKFLOWREQUEST']._serialized_start=1152
72
+ _globals['_RESUMEWORKFLOWREQUEST']._serialized_end=1243
73
+ _globals['_RESUMEWORKFLOWRESPONSE']._serialized_start=1245
74
+ _globals['_RESUMEWORKFLOWRESPONSE']._serialized_end=1269
75
+ _globals['_DELETEWORKFLOWREQUEST']._serialized_start=1271
76
+ _globals['_DELETEWORKFLOWREQUEST']._serialized_end=1374
77
+ _globals['_DELETEWORKFLOWRESPONSE']._serialized_start=1376
78
+ _globals['_DELETEWORKFLOWRESPONSE']._serialized_end=1420
79
+ _globals['_GETWORKFLOWREQUEST']._serialized_start=1422
80
+ _globals['_GETWORKFLOWREQUEST']._serialized_end=1463
81
+ _globals['_GETWORKFLOWRESPONSE']._serialized_start=1465
82
+ _globals['_GETWORKFLOWRESPONSE']._serialized_end=1528
83
+ _globals['_SETAGENTRUNTIMEPOLICYREQUEST']._serialized_start=1530
84
+ _globals['_SETAGENTRUNTIMEPOLICYREQUEST']._serialized_end=1650
85
+ _globals['_SETAGENTRUNTIMEPOLICYRESPONSE']._serialized_start=1652
86
+ _globals['_SETAGENTRUNTIMEPOLICYRESPONSE']._serialized_end=1683
87
+ _globals['_SETAGENTLIFECYCLEPOLICYREQUEST']._serialized_start=1685
88
+ _globals['_SETAGENTLIFECYCLEPOLICYREQUEST']._serialized_end=1809
89
+ _globals['_SETAGENTLIFECYCLEPOLICYRESPONSE']._serialized_start=1811
90
+ _globals['_SETAGENTLIFECYCLEPOLICYRESPONSE']._serialized_end=1844
91
+ _globals['_DELETEAGENTREQUEST']._serialized_start=1846
92
+ _globals['_DELETEAGENTREQUEST']._serialized_end=1907
93
+ _globals['_DELETEAGENTRESPONSE']._serialized_start=1909
94
+ _globals['_DELETEAGENTRESPONSE']._serialized_end=1930
95
+ _globals['_WORKFLOWLIFECYCLEPOLICYACTION']._serialized_start=1933
96
+ _globals['_WORKFLOWLIFECYCLEPOLICYACTION']._serialized_end=2068
97
+ _globals['_WORKFLOWLIFECYCLEPOLICYRULE']._serialized_start=2071
98
+ _globals['_WORKFLOWLIFECYCLEPOLICYRULE']._serialized_end=2261
99
+ _globals['_WORKFLOWLIFECYCLEPOLICY']._serialized_start=2263
100
+ _globals['_WORKFLOWLIFECYCLEPOLICY']._serialized_end=2346
101
+ _globals['_SETWORKFLOWLIFECYCLEPOLICYREQUEST']._serialized_start=2348
102
+ _globals['_SETWORKFLOWLIFECYCLEPOLICYREQUEST']._serialized_end=2469
103
+ _globals['_SETWORKFLOWLIFECYCLEPOLICYRESPONSE']._serialized_start=2471
104
+ _globals['_SETWORKFLOWLIFECYCLEPOLICYRESPONSE']._serialized_end=2507
105
+ _globals['_GETWORKFLOWLIFECYCLEPOLICYREQUEST']._serialized_start=2509
106
+ _globals['_GETWORKFLOWLIFECYCLEPOLICYREQUEST']._serialized_end=2565
107
+ _globals['_GETWORKFLOWLIFECYCLEPOLICYRESPONSE']._serialized_start=2567
108
+ _globals['_GETWORKFLOWLIFECYCLEPOLICYRESPONSE']._serialized_end=2668
109
+ _globals['_LISTAGENTSREQUEST']._serialized_start=2670
110
+ _globals['_LISTAGENTSREQUEST']._serialized_end=2710
111
+ _globals['_LISTAGENTSRESPONSE']._serialized_start=2712
112
+ _globals['_LISTAGENTSRESPONSE']._serialized_end=2769
113
+ _globals['_AGENT']._serialized_start=2772
114
+ _globals['_AGENT']._serialized_end=2947
115
+ _globals['_GETAGENTRUNTIMEPOLICYREQUEST']._serialized_start=2949
116
+ _globals['_GETAGENTRUNTIMEPOLICYREQUEST']._serialized_end=3020
117
+ _globals['_GETAGENTRUNTIMEPOLICYRESPONSE']._serialized_start=3022
118
+ _globals['_GETAGENTRUNTIMEPOLICYRESPONSE']._serialized_end=3102
119
+ _globals['_GETAGENTLIFECYCLEPOLICYREQUEST']._serialized_start=3104
120
+ _globals['_GETAGENTLIFECYCLEPOLICYREQUEST']._serialized_end=3177
121
+ _globals['_GETAGENTLIFECYCLEPOLICYRESPONSE']._serialized_start=3179
122
+ _globals['_GETAGENTLIFECYCLEPOLICYRESPONSE']._serialized_end=3263
123
+ _globals['_APPROVEWORKFLOWREQUEST']._serialized_start=3265
124
+ _globals['_APPROVEWORKFLOWREQUEST']._serialized_end=3362
125
+ _globals['_APPROVEWORKFLOWRESPONSE']._serialized_start=3364
126
+ _globals['_APPROVEWORKFLOWRESPONSE']._serialized_end=3389
127
+ _globals['_REJECTWORKFLOWREQUEST']._serialized_start=3391
128
+ _globals['_REJECTWORKFLOWREQUEST']._serialized_end=3487
129
+ _globals['_SUBMITINPUTREQUEST']._serialized_start=3489
130
+ _globals['_SUBMITINPUTREQUEST']._serialized_end=3604
131
+ _globals['_SUBMITINPUTRESPONSE']._serialized_start=3606
132
+ _globals['_SUBMITINPUTRESPONSE']._serialized_end=3627
133
+ _globals['_GETAPPROVALAUDITREQUEST']._serialized_start=3629
134
+ _globals['_GETAPPROVALAUDITREQUEST']._serialized_end=3675
135
+ _globals['_GETAPPROVALAUDITRESPONSE']._serialized_start=3677
136
+ _globals['_GETAPPROVALAUDITRESPONSE']._serialized_end=3755
137
+ _globals['_GETAPPROVALAUDITBYIDREQUEST']._serialized_start=3757
138
+ _globals['_GETAPPROVALAUDITBYIDREQUEST']._serialized_end=3807
139
+ _globals['_GETAPPROVALAUDITBYIDRESPONSE']._serialized_start=3809
140
+ _globals['_GETAPPROVALAUDITBYIDRESPONSE']._serialized_end=3890
141
+ _globals['_GETINPUTAUDITREQUEST']._serialized_start=3892
142
+ _globals['_GETINPUTAUDITREQUEST']._serialized_end=3935
143
+ _globals['_GETINPUTAUDITRESPONSE']._serialized_start=3937
144
+ _globals['_GETINPUTAUDITRESPONSE']._serialized_end=4009
145
+ _globals['_GETWORKFLOWPOLICYAUDITREQUEST']._serialized_start=4011
146
+ _globals['_GETWORKFLOWPOLICYAUDITREQUEST']._serialized_end=4063
147
+ _globals['_GETWORKFLOWPOLICYAUDITRESPONSE']._serialized_start=4065
148
+ _globals['_GETWORKFLOWPOLICYAUDITRESPONSE']._serialized_end=4155
149
+ _globals['_GETAGENTPOLICYAUDITREQUEST']._serialized_start=4157
150
+ _globals['_GETAGENTPOLICYAUDITREQUEST']._serialized_end=4226
151
+ _globals['_GETAGENTPOLICYAUDITRESPONSE']._serialized_start=4228
152
+ _globals['_GETAGENTPOLICYAUDITRESPONSE']._serialized_end=4312
153
+ _globals['_GETAUDITLOGREQUEST']._serialized_start=4314
154
+ _globals['_GETAUDITLOGREQUEST']._serialized_end=4355
155
+ _globals['_GETAUDITLOGRESPONSE']._serialized_start=4357
156
+ _globals['_GETAUDITLOGRESPONSE']._serialized_end=4421
157
+ _globals['_AUDITENTRY']._serialized_start=4424
158
+ _globals['_AUDITENTRY']._serialized_end=4679
159
+ _globals['_APPROVALAUDITRECORD']._serialized_start=4682
160
+ _globals['_APPROVALAUDITRECORD']._serialized_end=5013
161
+ _globals['_INPUTAUDITRECORD']._serialized_start=5016
162
+ _globals['_INPUTAUDITRECORD']._serialized_end=5356
163
+ _globals['_WORKFLOWPOLICYAUDITRECORD']._serialized_start=5359
164
+ _globals['_WORKFLOWPOLICYAUDITRECORD']._serialized_end=5621
165
+ _globals['_AGENTPOLICYAUDITRECORD']._serialized_start=5624
166
+ _globals['_AGENTPOLICYAUDITRECORD']._serialized_end=5822
167
+ _globals['_REJECTWORKFLOWRESPONSE']._serialized_start=5824
168
+ _globals['_REJECTWORKFLOWRESPONSE']._serialized_end=5848
169
+ _globals['_ACTIVATEWORKFLOWREQUEST']._serialized_start=5850
170
+ _globals['_ACTIVATEWORKFLOWREQUEST']._serialized_end=5916
171
+ _globals['_ACTIVATEWORKFLOWRESPONSE']._serialized_start=5918
172
+ _globals['_ACTIVATEWORKFLOWRESPONSE']._serialized_end=5944
173
+ _globals['_RESOLVEINTERRUPTEDWORKFLOWREQUEST']._serialized_start=5946
174
+ _globals['_RESOLVEINTERRUPTEDWORKFLOWREQUEST']._serialized_end=6022
175
+ _globals['_RESOLVEINTERRUPTEDWORKFLOWRESPONSE']._serialized_start=6024
176
+ _globals['_RESOLVEINTERRUPTEDWORKFLOWRESPONSE']._serialized_end=6060
177
+ _globals['_LISTWORKFLOWRUNSREQUEST']._serialized_start=6062
178
+ _globals['_LISTWORKFLOWRUNSREQUEST']._serialized_end=6108
179
+ _globals['_RUN']._serialized_start=6111
180
+ _globals['_RUN']._serialized_end=6317
181
+ _globals['_LISTWORKFLOWRUNSRESPONSE']._serialized_start=6319
182
+ _globals['_LISTWORKFLOWRUNSRESPONSE']._serialized_end=6378
183
+ _globals['_GETREQUESTINFOREQUEST']._serialized_start=6380
184
+ _globals['_GETREQUESTINFOREQUEST']._serialized_end=6423
185
+ _globals['_REQUESTINFO']._serialized_start=6426
186
+ _globals['_REQUESTINFO']._serialized_end=6860
187
+ _globals['_GETREQUESTINFORESPONSE']._serialized_start=6862
188
+ _globals['_GETREQUESTINFORESPONSE']._serialized_end=6930
189
+ _globals['_GETWORKFLOWMETRICSREQUEST']._serialized_start=6932
190
+ _globals['_GETWORKFLOWMETRICSREQUEST']._serialized_end=6980
191
+ _globals['_GETWORKFLOWMETRICSRESPONSE']._serialized_start=6983
192
+ _globals['_GETWORKFLOWMETRICSRESPONSE']._serialized_end=7334
193
+ _globals['_GETWORKFLOWMETRICSRESPONSE_TOOLFAILURECOUNTSENTRY']._serialized_start=7278
194
+ _globals['_GETWORKFLOWMETRICSRESPONSE_TOOLFAILURECOUNTSENTRY']._serialized_end=7334
195
+ _globals['_SETWORKFLOWCONFIGREQUEST']._serialized_start=7336
196
+ _globals['_SETWORKFLOWCONFIGREQUEST']._serialized_end=7429
197
+ _globals['_SETWORKFLOWCONFIGRESPONSE']._serialized_start=7431
198
+ _globals['_SETWORKFLOWCONFIGRESPONSE']._serialized_end=7500
199
+ _globals['_WORKFLOWSERVICE']._serialized_start=8127
200
+ _globals['_WORKFLOWSERVICE']._serialized_end=11300
201
+ # @@protoc_insertion_point(module_scope)
@@ -109,6 +109,11 @@ class WorkflowServiceStub:
109
109
  request_serializer=boundflow_dot_v1_dot_lifecycle__pb2.GetAgentLifecyclePolicyRequest.SerializeToString,
110
110
  response_deserializer=boundflow_dot_v1_dot_lifecycle__pb2.GetAgentLifecyclePolicyResponse.FromString,
111
111
  _registered_method=True)
112
+ self.ListAgents = channel.unary_unary(
113
+ '/boundflow.v1.WorkflowService/ListAgents',
114
+ request_serializer=boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsRequest.SerializeToString,
115
+ response_deserializer=boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsResponse.FromString,
116
+ _registered_method=True)
112
117
  self.ApproveWorkflow = channel.unary_unary(
113
118
  '/boundflow.v1.WorkflowService/ApproveWorkflow',
114
119
  request_serializer=boundflow_dot_v1_dot_lifecycle__pb2.ApproveWorkflowRequest.SerializeToString,
@@ -289,6 +294,12 @@ class WorkflowServiceServicer:
289
294
  context.set_details('Method not implemented!')
290
295
  raise NotImplementedError('Method not implemented!')
291
296
 
297
+ def ListAgents(self, request, context):
298
+ """Missing associated documentation comment in .proto file."""
299
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
300
+ context.set_details('Method not implemented!')
301
+ raise NotImplementedError('Method not implemented!')
302
+
292
303
  def ApproveWorkflow(self, request, context):
293
304
  """Missing associated documentation comment in .proto file."""
294
305
  context.set_code(grpc.StatusCode.UNIMPLEMENTED)
@@ -459,6 +470,11 @@ def add_WorkflowServiceServicer_to_server(servicer, server):
459
470
  request_deserializer=boundflow_dot_v1_dot_lifecycle__pb2.GetAgentLifecyclePolicyRequest.FromString,
460
471
  response_serializer=boundflow_dot_v1_dot_lifecycle__pb2.GetAgentLifecyclePolicyResponse.SerializeToString,
461
472
  ),
473
+ 'ListAgents': grpc.unary_unary_rpc_method_handler(
474
+ servicer.ListAgents,
475
+ request_deserializer=boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsRequest.FromString,
476
+ response_serializer=boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsResponse.SerializeToString,
477
+ ),
462
478
  'ApproveWorkflow': grpc.unary_unary_rpc_method_handler(
463
479
  servicer.ApproveWorkflow,
464
480
  request_deserializer=boundflow_dot_v1_dot_lifecycle__pb2.ApproveWorkflowRequest.FromString,
@@ -950,6 +966,33 @@ class WorkflowService:
950
966
  metadata,
951
967
  _registered_method=True)
952
968
 
969
+ @staticmethod
970
+ def ListAgents(request,
971
+ target,
972
+ options=(),
973
+ channel_credentials=None,
974
+ call_credentials=None,
975
+ insecure=False,
976
+ compression=None,
977
+ wait_for_ready=None,
978
+ timeout=None,
979
+ metadata=None):
980
+ return grpc.experimental.unary_unary(
981
+ request,
982
+ target,
983
+ '/boundflow.v1.WorkflowService/ListAgents',
984
+ boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsRequest.SerializeToString,
985
+ boundflow_dot_v1_dot_lifecycle__pb2.ListAgentsResponse.FromString,
986
+ options,
987
+ channel_credentials,
988
+ insecure,
989
+ call_credentials,
990
+ compression,
991
+ wait_for_ready,
992
+ timeout,
993
+ metadata,
994
+ _registered_method=True)
995
+
953
996
  @staticmethod
954
997
  def ApproveWorkflow(request,
955
998
  target,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: boundflow
3
- Version: 0.6.0
3
+ Version: 0.7.0.dev7
4
4
  Summary: BoundFlow Python SDK — build governed fleets of agents against a self-hostable control plane.
5
5
  License-Expression: MIT
6
6
  Keywords: agents,llm,orchestration,control-plane,governance