metaflow 2.18.9__py2.py3-none-any.whl → 2.18.11__py2.py3-none-any.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.
metaflow/cards.py CHANGED
@@ -10,6 +10,9 @@ from metaflow.plugins.cards.card_modules.components import (
10
10
  ProgressBar,
11
11
  ValueBox,
12
12
  PythonCode,
13
+ EventsTimeline,
14
+ JSONViewer,
15
+ YAMLViewer,
13
16
  )
14
17
  from metaflow.plugins.cards.card_modules.basic import (
15
18
  DefaultCard,
metaflow/parameters.py CHANGED
@@ -495,6 +495,10 @@ def add_custom_parameters(deploy_mode=False):
495
495
  # deploy_mode determines whether deploy-time functions should or should
496
496
  # not be evaluated for this command
497
497
  def wrapper(cmd):
498
+ # Save the original params once, if they haven't been saved before.
499
+ if not hasattr(cmd, "original_params"):
500
+ cmd.original_params = list(cmd.params)
501
+
498
502
  cmd.has_flow_params = True
499
503
  # Iterate over parameters in reverse order so cmd.params lists options
500
504
  # in the order they are defined in the FlowSpec subclass
@@ -1423,11 +1423,7 @@ class ArgoWorkflows(object):
1423
1423
  dag_tasks.append(dag_task)
1424
1424
  # End the workflow if we have reached the end of the flow
1425
1425
  if node.type == "end":
1426
- return [
1427
- Template(self.flow.name).dag(
1428
- DAGTemplate().fail_fast().tasks(dag_tasks)
1429
- )
1430
- ] + templates, dag_tasks
1426
+ return templates, dag_tasks
1431
1427
  # For split nodes traverse all the children
1432
1428
  if node.type == "split":
1433
1429
  for n in node.out_funcs:
@@ -1550,7 +1546,6 @@ class ArgoWorkflows(object):
1550
1546
  parent_foreach,
1551
1547
  seen,
1552
1548
  )
1553
-
1554
1549
  return _visit(
1555
1550
  self.graph[self._matching_conditional_join(node)],
1556
1551
  exit_node,
@@ -1806,7 +1801,11 @@ class ArgoWorkflows(object):
1806
1801
  for daemon_template in self._daemon_templates()
1807
1802
  ]
1808
1803
 
1809
- templates, _ = _visit(node=self.graph["start"], dag_tasks=daemon_tasks)
1804
+ templates, dag_tasks = _visit(node=self.graph["start"], dag_tasks=daemon_tasks)
1805
+ # Add the DAG template only after fully traversing the graph so we are guaranteed to have all the dag_tasks collected.
1806
+ templates.append(
1807
+ Template(self.flow.name).dag(DAGTemplate().fail_fast().tasks(dag_tasks))
1808
+ )
1810
1809
  return templates
1811
1810
 
1812
1811
  # Visit every node and yield ContainerTemplates.
@@ -2,7 +2,7 @@ import base64
2
2
  import json
3
3
  import os
4
4
  from .card import MetaflowCard, MetaflowCardComponent, with_default_component_id
5
- from .convert_to_native_type import TaskToDict
5
+ from .convert_to_native_type import TaskToDict, MAX_ARTIFACT_SIZE
6
6
  import uuid
7
7
  import inspect
8
8
 
@@ -376,9 +376,14 @@ class TaskInfoComponent(MetaflowCardComponent):
376
376
  components=[],
377
377
  runtime=False,
378
378
  flow=None,
379
+ max_artifact_size=None,
379
380
  ):
380
381
  self._task = task
381
382
  self._only_repr = only_repr
383
+ # Use the global MAX_ARTIFACT_SIZE constant if not specified
384
+ self._max_artifact_size = (
385
+ max_artifact_size if max_artifact_size is not None else MAX_ARTIFACT_SIZE
386
+ )
382
387
  self._graph = graph
383
388
  self._components = components
384
389
  self._page_title = page_title
@@ -394,9 +399,9 @@ class TaskInfoComponent(MetaflowCardComponent):
394
399
  a dictionary of form:
395
400
  dict(metadata = {},components= [])
396
401
  """
397
- task_data_dict = TaskToDict(only_repr=self._only_repr)(
398
- self._task, graph=self._graph
399
- )
402
+ task_data_dict = TaskToDict(
403
+ only_repr=self._only_repr, max_artifact_size=self._max_artifact_size
404
+ )(self._task, graph=self._graph)
400
405
  # ignore the name as an artifact
401
406
  if "name" in task_data_dict["data"]:
402
407
  del task_data_dict["data"]["name"]
@@ -693,10 +698,14 @@ class DefaultCard(MetaflowCard):
693
698
  **kwargs
694
699
  ):
695
700
  self._only_repr = True
701
+ # Default max artifact size uses the global MAX_ARTIFACT_SIZE constant (200MB)
702
+ self._max_artifact_size = MAX_ARTIFACT_SIZE
696
703
  self._graph = None if graph is None else transform_flow_graph(graph)
697
704
  self._flow = flow
698
705
  if "only_repr" in options:
699
706
  self._only_repr = options["only_repr"]
707
+ if "max_artifact_size" in options:
708
+ self._max_artifact_size = options["max_artifact_size"]
700
709
  self._components = components
701
710
 
702
711
  def render(self, task, runtime=False):
@@ -710,6 +719,7 @@ class DefaultCard(MetaflowCard):
710
719
  components=self._components,
711
720
  runtime=runtime,
712
721
  flow=self._flow,
722
+ max_artifact_size=self._max_artifact_size,
713
723
  ).render()
714
724
  pt = self._get_mustache()
715
725
  data_dict = dict(
@@ -1 +1 @@
1
- @import"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap";code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:#ffffff80}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}:root{--bg: #ffffff;--black: #333;--blue: #0c66de;--dk-grey: #767676;--dk-primary: #ef863b;--dk-secondary: #13172d;--dk-tertiary: #0f426e;--error: #cf483e;--grey: rgba(0, 0, 0, .125);--highlight: #f8d9d8;--lt-blue: #4fa7ff;--lt-grey: #f3f3f3;--lt-lt-grey: #f9f9f9;--lt-primary: #ffcb8b;--lt-secondary: #434d81;--lt-tertiary: #4189c9;--primary: #faab4a;--quadrary: #f8d9d8;--secondary: #2e3454;--tertiary: #2a679d;--white: #ffffff;--component-spacer: 3rem;--aside-width: 20rem;--embed-card-min-height: 12rem;--mono-font: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace}html,body{margin:0;min-height:100vh;overflow-y:visible;padding:0;width:100%}.card_app{width:100%;min-height:100vh}.embed .card_app{min-height:var(--embed-card-min-height)}.mf-card *{box-sizing:border-box}.mf-card{background:var(--bg);color:var(--black);font-family:Roboto,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:14px;font-weight:400;line-height:1.5;text-size-adjust:100%;margin:0;min-height:100vh;overflow-y:visible;padding:0;text-align:left;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;width:100%}.embed .mf-card{min-height:var(--embed-card-min-height)}.mf-card :is(.mono,code.mono,pre.mono){font-family:var(--mono-font);font-weight:lighter}.mf-card :is(table,th,td){border-spacing:1px;text-align:center;color:var(--black)}.mf-card table{position:relative;min-width:100%;table-layout:inherit!important}.mf-card td{padding:.66rem 1.25rem;background:var(--lt-lt-grey);border:none}.mf-card th{border:none;color:var(--dk-grey);font-weight:400;padding:.5rem}.mf-card :is(h1,h2,h3,h4,h5){font-weight:700;margin:.5rem 0}.mf-card ul{margin:0;padding:0}.mf-card p{margin:0 0 1rem}.mf-card p:last-of-type{margin:0}.mf-card button{font-size:1rem}.mf-card .textButton{cursor:pointer;text-align:left;background:none;border:1px solid transparent;outline:none;padding:0}.mf-card :is(button.textButton:focus,a:focus,button.textButton:active){border:1px dashed var(--grey);background:transparent}.mf-card button.textButton:hover{color:var(--blue);text-decoration:none}.mf-card :is(:not(pre)>code[class*=language-],pre[class*=language-]){background:transparent!important;text-shadow:none;-webkit-user-select:auto;user-select:auto}aside.svelte-1okdv0e{display:none;line-height:2;text-align:left}@media (min-width: 60rem){aside.svelte-1okdv0e{display:flex;flex-direction:column;height:100vh;justify-content:space-between;padding:2.5rem 0 1.5rem 1.5rem;position:fixed;width:var(--aside-width)}}.embed aside{display:none}aside ul{list-style-type:none}aside a,aside button,aside a:visited{text-decoration:none;cursor:pointer;font-weight:700;color:var(--black)}aside a:hover,aside button:hover{text-decoration:underline}.logoContainer svg{width:100%;max-width:140px;margin-bottom:3.75rem;height:auto}.idCell.svelte-pt8vzv{font-weight:700;text-align:right;background:var(--lt-grey);width:12%}.codeCell.svelte-pt8vzv{text-align:left;-webkit-user-select:all;user-select:all}.container.svelte-ubs992{width:100%;overflow:auto}table.svelte-ubs992{width:100%}:root{--dag-border: #282828;--dag-bg-static: var(--lt-grey);--dag-bg-success: #a5d46a;--dag-bg-running: #ffdf80;--dag-bg-error: #ffa080;--dag-connector: #cccccc;--dag-gap: 5rem;--dag-step-height: 6.25rem;--dag-step-width: 11.25rem;--dag-selected: #ffd700}.connectorwrapper.svelte-19jpdwh{transform-origin:0 0;position:absolute;z-index:0;min-width:var(--strokeWidth)}.flip.svelte-19jpdwh{transform:scaleX(-1)}.path.svelte-19jpdwh{--strokeWidth:.5rem;--strokeColor:var(--dag-connector);--borderRadius:1.25rem;box-sizing:border-box}.straightLine.svelte-19jpdwh{position:absolute;top:0;bottom:0;left:0;right:0;border-left:var(--strokeWidth) solid var(--strokeColor)}.loop.svelte-19jpdwh{position:absolute;top:-50%;left:0;width:100%;height:100%;border-radius:var(--borderRadius);border:var(--strokeWidth) solid var(--strokeColor)}.topLeft.svelte-19jpdwh{position:absolute;top:0;left:0;right:50%;bottom:calc(var(--dag-gap) / 2 - var(--strokeWidth) / 2);border-radius:0 0 0 var(--borderRadius);border-left:var(--strokeWidth) solid var(--strokeColor);border-bottom:var(--strokeWidth) solid var(--strokeColor)}.bottomRight.svelte-19jpdwh{position:absolute;top:calc(100% - (var(--dag-gap) / 2 + var(--strokeWidth) / 2));left:50%;right:0;bottom:0;border-radius:0 var(--borderRadius) 0 0;border-top:var(--strokeWidth) solid var(--strokeColor);border-right:var(--strokeWidth) solid var(--strokeColor)}.wrapper.svelte-117ceti.svelte-117ceti{position:relative;z-index:1}.step.svelte-117ceti.svelte-117ceti{font-size:.75rem;padding:.5rem;color:var(--dk-grey)}.rectangle.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-static);border:1px solid var(--dag-border);box-sizing:border-box;position:relative;height:var(--dag-step-height);width:var(--dag-step-width)}.rectangle.error.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-error)}.rectangle.success.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-success)}.rectangle.running.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-running)}.level.svelte-117ceti.svelte-117ceti{z-index:-1;filter:contrast(.5);position:absolute}.inner.svelte-117ceti.svelte-117ceti{position:relative;height:100%;width:100%}.name.svelte-117ceti.svelte-117ceti{font-weight:700;overflow:hidden;text-overflow:ellipsis;display:block}.description.svelte-117ceti.svelte-117ceti{position:absolute;max-height:4rem;bottom:0;left:0;right:0;overflow:hidden;-webkit-line-clamp:4;line-clamp:4;display:-webkit-box;-webkit-box-orient:vertical}.overflown.description.svelte-117ceti.svelte-117ceti{cursor:help}.current.svelte-117ceti .rectangle.svelte-117ceti{box-shadow:0 0 10px var(--dag-selected)}.levelstoshow.svelte-117ceti.svelte-117ceti{position:absolute;bottom:100%;right:0;font-size:.75rem;font-weight:100;text-align:right}.stepwrapper.svelte-18aex7a{display:flex;align-items:center;flex-direction:column;width:100%;position:relative;min-width:var(--dag-step-width)}.childwrapper.svelte-18aex7a{display:flex;width:100%}.gap.svelte-18aex7a{height:var(--dag-gap)}.title.svelte-117s0ws{text-align:left}.subtitle.svelte-lu9pnn{font-size:1rem;text-align:left}header.svelte-1ugmt5d{margin-bottom:var(--component-spacer)}figure.svelte-1x96yvr{background:var(--lt-grey);padding:1rem;border-radius:5px;text-align:center;margin:0 auto var(--component-spacer)}@media (min-width: 60rem){figure.svelte-1x96yvr{margin-bottom:0}}img.svelte-1x96yvr{max-width:100%;max-height:500px}.label.svelte-1x96yvr{font-weight:700;margin:.5rem 0}.description.svelte-1x96yvr{font-size:.9rem;font-style:italic;text-align:center;margin:.5rem 0}.log.svelte-1jhmsu{background:var(--lt-grey)!important;font-size:.9rem;padding:2rem}.page.svelte-v7ihqd:last-of-type{margin-bottom:var(--component-spacer)}.page:last-of-type section:last-of-type hr{display:none}progress.svelte-ljrmzp::-webkit-progress-bar{background-color:#fff!important;min-width:100%}progress.svelte-ljrmzp{background-color:#fff;color:#326cded9!important}progress.svelte-ljrmzp::-moz-progress-bar{background-color:#326cde!important}table .container{background:transparent!important;font-size:10px!important;padding:0!important}table progress{height:4px!important}.container.svelte-ljrmzp{display:flex;align-items:center;justify-content:center;font-size:12px;border-radius:3px;background:#edf5ff;padding:3rem}.inner.svelte-ljrmzp{max-width:410px;width:100%;text-align:center}.info.svelte-ljrmzp{display:flex;justify-content:space-between}table .info{text-align:left;flex-direction:column}label.svelte-ljrmzp{font-weight:700}.labelValue.svelte-ljrmzp{border-left:1px solid rgba(0,0,0,.1);margin-left:.25rem;padding-left:.5rem}.details.svelte-ljrmzp{font-family:var(--mono-font);font-size:8px;color:#333433;line-height:18px;overflow:hidden;white-space:nowrap}progress.svelte-ljrmzp{width:100%;border:none;border-radius:5px;height:8px;background:#fff}.heading.svelte-17n0qr8{margin-bottom:1.5rem}.sectionItems.svelte-17n0qr8{display:block}.sectionItems .imageContainer{max-height:500px}.container.svelte-17n0qr8{scroll-margin:var(--component-spacer)}hr.svelte-17n0qr8{background:var(--grey);border:none;height:1px;margin:var(--component-spacer) 0;padding:0}@media (min-width: 60rem){.sectionItems.svelte-17n0qr8{display:grid;grid-gap:2rem}}.value-box.svelte-175x1n5.svelte-175x1n5{border-radius:.5rem;padding:1.5rem;box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;border:1px solid #e5e7eb;background:#fff;min-height:120px;display:flex;align-items:center}.value-box-content.svelte-175x1n5.svelte-175x1n5{width:100%}.value-box-title.svelte-175x1n5.svelte-175x1n5{font-size:.875rem;font-weight:500;color:#6b7280;margin:0 0 .5rem;text-transform:uppercase;letter-spacing:.025em}.value-box-value.svelte-175x1n5.svelte-175x1n5{font-size:2rem;font-weight:700;color:#111827;line-height:1.2;margin:0 0 .5rem}.value-box-subtitle.svelte-175x1n5.svelte-175x1n5{font-size:.875rem;color:#6b7280;margin:0 0 .5rem}.value-box-change.svelte-175x1n5.svelte-175x1n5{font-size:.75rem;font-weight:500;color:#059669;text-transform:uppercase;letter-spacing:.025em}.value-box.default.svelte-175x1n5.svelte-175x1n5{background:#fff;border-color:#e5e7eb}.value-box.bg-gradient-indigo-purple.svelte-175x1n5.svelte-175x1n5{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border:none}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-title.svelte-175x1n5,.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-subtitle.svelte-175x1n5{color:#fffc}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#fff}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#ffffffe6}.value-box.success.svelte-175x1n5.svelte-175x1n5{background:#f0fdf4;border-color:#bbf7d0}.value-box.success.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#065f46}.value-box.success.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#059669}.value-box.warning.svelte-175x1n5.svelte-175x1n5{background:#fffbeb;border-color:#fed7aa}.value-box.warning.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#92400e}.value-box.warning.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#d97706}.value-box.danger.svelte-175x1n5.svelte-175x1n5{background:#fef2f2;border-color:#fecaca}.value-box.danger.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#991b1b}.value-box.danger.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#dc2626}@media (max-width: 640px){.value-box.svelte-175x1n5.svelte-175x1n5{padding:1rem;min-height:100px}.value-box-value.svelte-175x1n5.svelte-175x1n5{font-size:1.5rem}}table .value-box{min-height:auto;padding:.75rem;margin:.25rem 0}table .value-box-value{font-size:1.25rem}td.svelte-gl9h79{text-align:left}td.labelColumn.svelte-gl9h79{text-align:right;background-color:var(--lt-grey);font-weight:700;width:12%;white-space:nowrap}.tableContainer.svelte-q3hq57{overflow:auto}th.svelte-q3hq57{position:sticky;top:-1px;z-index:2;white-space:nowrap;background:var(--white)}.mainContainer.svelte-mqeomk{max-width:110rem}main.svelte-mqeomk{flex:0 1 auto;max-width:100rem;padding:1.5rem}@media (min-width: 60rem){main.svelte-mqeomk{margin-left:var(--aside-width)}}.embed main{margin:0 auto;min-width:80%}.modal.svelte-1hhf5ym{align-items:center;background:#00000080;bottom:0;cursor:pointer;display:flex;height:100%;justify-content:center;left:0;overflow:hidden;position:fixed;right:0;top:0;width:100%;z-index:100}.modalContainer>*{background-color:#fff;border-radius:5px;cursor:default;flex:0 1 auto;padding:1rem;position:relative}.modal img{max-height:80vh!important}.cancelButton.svelte-1hhf5ym{color:#fff;cursor:pointer;font-size:2rem;position:absolute;right:1rem;top:1rem}.cancelButton.svelte-1hhf5ym:hover{color:var(--blue)}.nav.svelte-1kdpgko.svelte-1kdpgko{border-radius:0 0 5px;display:none;margin:0;top:0}ul.navList.svelte-1kdpgko.svelte-1kdpgko{list-style-type:none}ul.navList.svelte-1kdpgko ul.svelte-1kdpgko{margin:.5rem 1rem 2rem}.navList.svelte-1kdpgko li.svelte-1kdpgko{display:block;margin:0}.navItem.svelte-1kdpgko li.svelte-1kdpgko:hover{color:var(--blue)}.pageId.svelte-1kdpgko.svelte-1kdpgko{display:block;border-bottom:1px solid var(--grey);padding:0 .5rem;margin-bottom:1rem}@media (min-width: 60rem){.nav.svelte-1kdpgko.svelte-1kdpgko{display:block}ul.navList.svelte-1kdpgko.svelte-1kdpgko{text-align:left}.navList.svelte-1kdpgko li.svelte-1kdpgko{display:block;margin:.5rem 0}}.container.svelte-teyund{width:100%;display:flex;flex-direction:column;position:relative}
1
+ @import"https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap";code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:#ffffff80}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}:root{--bg: #ffffff;--black: #333;--blue: #0c66de;--dk-grey: #767676;--dk-primary: #ef863b;--dk-secondary: #13172d;--dk-tertiary: #0f426e;--error: #cf483e;--grey: rgba(0, 0, 0, .125);--highlight: #f8d9d8;--lt-blue: #4fa7ff;--lt-grey: #f3f3f3;--lt-lt-grey: #f9f9f9;--lt-primary: #ffcb8b;--lt-secondary: #434d81;--lt-tertiary: #4189c9;--primary: #faab4a;--quadrary: #f8d9d8;--secondary: #2e3454;--tertiary: #2a679d;--white: #ffffff;--component-spacer: 3rem;--aside-width: 20rem;--embed-card-min-height: 12rem;--mono-font: ui-monospace, Menlo, Monaco, "Cascadia Mono", "Segoe UI Mono", "Roboto Mono", "Oxygen Mono", "Ubuntu Monospace", "Source Code Pro", "Fira Mono", "Droid Sans Mono", "Courier New", monospace}html,body{margin:0;min-height:100vh;overflow-y:visible;padding:0;width:100%}.card_app{width:100%;min-height:100vh}.embed .card_app{min-height:var(--embed-card-min-height)}.mf-card *{box-sizing:border-box}.mf-card{background:var(--bg);color:var(--black);font-family:Roboto,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;font-size:14px;font-weight:400;line-height:1.5;text-size-adjust:100%;margin:0;min-height:100vh;overflow-y:visible;padding:0;text-align:left;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;width:100%}.embed .mf-card{min-height:var(--embed-card-min-height)}.mf-card :is(.mono,code.mono,pre.mono){font-family:var(--mono-font);font-weight:lighter}.mf-card :is(table,th,td){border-spacing:1px;text-align:center;color:var(--black)}.mf-card table{position:relative;min-width:100%;table-layout:inherit!important}.mf-card td{padding:.66rem 1.25rem;background:var(--lt-lt-grey);border:none}.mf-card th{border:none;color:var(--dk-grey);font-weight:400;padding:.5rem}.mf-card :is(h1,h2,h3,h4,h5){font-weight:700;margin:.5rem 0}.mf-card ul{margin:0;padding:0}.mf-card p{margin:0 0 1rem}.mf-card p:last-of-type{margin:0}.mf-card button{font-size:1rem}.mf-card .textButton{cursor:pointer;text-align:left;background:none;border:1px solid transparent;outline:none;padding:0}.mf-card :is(button.textButton:focus,a:focus,button.textButton:active){border:1px dashed var(--grey);background:transparent}.mf-card button.textButton:hover{color:var(--blue);text-decoration:none}.mf-card :is(:not(pre)>code[class*=language-],pre[class*=language-]){background:transparent!important;text-shadow:none;-webkit-user-select:auto;user-select:auto}aside.svelte-1okdv0e{display:none;line-height:2;text-align:left}@media (min-width: 60rem){aside.svelte-1okdv0e{display:flex;flex-direction:column;height:100vh;justify-content:space-between;padding:2.5rem 0 1.5rem 1.5rem;position:fixed;width:var(--aside-width)}}.embed aside{display:none}aside ul{list-style-type:none}aside a,aside button,aside a:visited{text-decoration:none;cursor:pointer;font-weight:700;color:var(--black)}aside a:hover,aside button:hover{text-decoration:underline}.logoContainer svg{width:100%;max-width:140px;margin-bottom:3.75rem;height:auto}.idCell.svelte-pt8vzv{font-weight:700;text-align:right;background:var(--lt-grey);width:12%}.codeCell.svelte-pt8vzv{text-align:left;-webkit-user-select:all;user-select:all}.container.svelte-ubs992{width:100%;overflow:auto}table.svelte-ubs992{width:100%}:root{--dag-border: #282828;--dag-bg-static: var(--lt-grey);--dag-bg-success: #a5d46a;--dag-bg-running: #ffdf80;--dag-bg-error: #ffa080;--dag-connector: #cccccc;--dag-gap: 5rem;--dag-step-height: 6.25rem;--dag-step-width: 11.25rem;--dag-selected: #ffd700}.connectorwrapper.svelte-19jpdwh{transform-origin:0 0;position:absolute;z-index:0;min-width:var(--strokeWidth)}.flip.svelte-19jpdwh{transform:scaleX(-1)}.path.svelte-19jpdwh{--strokeWidth:.5rem;--strokeColor:var(--dag-connector);--borderRadius:1.25rem;box-sizing:border-box}.straightLine.svelte-19jpdwh{position:absolute;top:0;bottom:0;left:0;right:0;border-left:var(--strokeWidth) solid var(--strokeColor)}.loop.svelte-19jpdwh{position:absolute;top:-50%;left:0;width:100%;height:100%;border-radius:var(--borderRadius);border:var(--strokeWidth) solid var(--strokeColor)}.topLeft.svelte-19jpdwh{position:absolute;top:0;left:0;right:50%;bottom:calc(var(--dag-gap) / 2 - var(--strokeWidth) / 2);border-radius:0 0 0 var(--borderRadius);border-left:var(--strokeWidth) solid var(--strokeColor);border-bottom:var(--strokeWidth) solid var(--strokeColor)}.bottomRight.svelte-19jpdwh{position:absolute;top:calc(100% - (var(--dag-gap) / 2 + var(--strokeWidth) / 2));left:50%;right:0;bottom:0;border-radius:0 var(--borderRadius) 0 0;border-top:var(--strokeWidth) solid var(--strokeColor);border-right:var(--strokeWidth) solid var(--strokeColor)}.wrapper.svelte-117ceti.svelte-117ceti{position:relative;z-index:1}.step.svelte-117ceti.svelte-117ceti{font-size:.75rem;padding:.5rem;color:var(--dk-grey)}.rectangle.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-static);border:1px solid var(--dag-border);box-sizing:border-box;position:relative;height:var(--dag-step-height);width:var(--dag-step-width)}.rectangle.error.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-error)}.rectangle.success.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-success)}.rectangle.running.svelte-117ceti.svelte-117ceti{background-color:var(--dag-bg-running)}.level.svelte-117ceti.svelte-117ceti{z-index:-1;filter:contrast(.5);position:absolute}.inner.svelte-117ceti.svelte-117ceti{position:relative;height:100%;width:100%}.name.svelte-117ceti.svelte-117ceti{font-weight:700;overflow:hidden;text-overflow:ellipsis;display:block}.description.svelte-117ceti.svelte-117ceti{position:absolute;max-height:4rem;bottom:0;left:0;right:0;overflow:hidden;-webkit-line-clamp:4;line-clamp:4;display:-webkit-box;-webkit-box-orient:vertical}.overflown.description.svelte-117ceti.svelte-117ceti{cursor:help}.current.svelte-117ceti .rectangle.svelte-117ceti{box-shadow:0 0 10px var(--dag-selected)}.levelstoshow.svelte-117ceti.svelte-117ceti{position:absolute;bottom:100%;right:0;font-size:.75rem;font-weight:100;text-align:right}.stepwrapper.svelte-18aex7a{display:flex;align-items:center;flex-direction:column;width:100%;position:relative;min-width:var(--dag-step-width)}.childwrapper.svelte-18aex7a{display:flex;width:100%}.gap.svelte-18aex7a{height:var(--dag-gap)}.title.svelte-117s0ws{text-align:left}.subtitle.svelte-lu9pnn{font-size:1rem;text-align:left}header.svelte-1ugmt5d{margin-bottom:var(--component-spacer)}figure.svelte-1x96yvr{background:var(--lt-grey);padding:1rem;border-radius:5px;text-align:center;margin:0 auto var(--component-spacer)}@media (min-width: 60rem){figure.svelte-1x96yvr{margin-bottom:0}}img.svelte-1x96yvr{max-width:100%;max-height:500px}.label.svelte-1x96yvr{font-weight:700;margin:.5rem 0}.description.svelte-1x96yvr{font-size:.9rem;font-style:italic;text-align:center;margin:.5rem 0}.log.svelte-1jhmsu{background:var(--lt-grey)!important;font-size:.9rem;padding:2rem}.page.svelte-v7ihqd:last-of-type{margin-bottom:var(--component-spacer)}.page:last-of-type section:last-of-type hr{display:none}progress.svelte-ljrmzp::-webkit-progress-bar{background-color:#fff!important;min-width:100%}progress.svelte-ljrmzp{background-color:#fff;color:#326cded9!important}progress.svelte-ljrmzp::-moz-progress-bar{background-color:#326cde!important}table .container{background:transparent!important;font-size:10px!important;padding:0!important}table progress{height:4px!important}.container.svelte-ljrmzp{display:flex;align-items:center;justify-content:center;font-size:12px;border-radius:3px;background:#edf5ff;padding:3rem}.inner.svelte-ljrmzp{max-width:410px;width:100%;text-align:center}.info.svelte-ljrmzp{display:flex;justify-content:space-between}table .info{text-align:left;flex-direction:column}label.svelte-ljrmzp{font-weight:700}.labelValue.svelte-ljrmzp{border-left:1px solid rgba(0,0,0,.1);margin-left:.25rem;padding-left:.5rem}.details.svelte-ljrmzp{font-family:var(--mono-font);font-size:8px;color:#333433;line-height:18px;overflow:hidden;white-space:nowrap}progress.svelte-ljrmzp{width:100%;border:none;border-radius:5px;height:8px;background:#fff}.heading.svelte-17n0qr8{margin-bottom:1.5rem}.sectionItems.svelte-17n0qr8{display:block}.sectionItems .imageContainer{max-height:500px}.container.svelte-17n0qr8{scroll-margin:var(--component-spacer)}hr.svelte-17n0qr8{background:var(--grey);border:none;height:1px;margin:var(--component-spacer) 0;padding:0}@media (min-width: 60rem){.sectionItems.svelte-17n0qr8{display:grid;grid-gap:2rem}}.value-box.svelte-175x1n5.svelte-175x1n5{border-radius:.5rem;padding:1.5rem;box-shadow:0 1px 3px #0000001a,0 1px 2px #0000000f;border:1px solid #e5e7eb;background:#fff;min-height:120px;display:flex;align-items:center}.value-box-content.svelte-175x1n5.svelte-175x1n5{width:100%}.value-box-title.svelte-175x1n5.svelte-175x1n5{font-size:.875rem;font-weight:500;color:#6b7280;margin:0 0 .5rem;text-transform:uppercase;letter-spacing:.025em}.value-box-value.svelte-175x1n5.svelte-175x1n5{font-size:2rem;font-weight:700;color:#111827;line-height:1.2;margin:0 0 .5rem}.value-box-subtitle.svelte-175x1n5.svelte-175x1n5{font-size:.875rem;color:#6b7280;margin:0 0 .5rem}.value-box-change.svelte-175x1n5.svelte-175x1n5{font-size:.75rem;font-weight:500;color:#059669;text-transform:uppercase;letter-spacing:.025em}.value-box.default.svelte-175x1n5.svelte-175x1n5{background:#fff;border-color:#e5e7eb}.value-box.bg-gradient-indigo-purple.svelte-175x1n5.svelte-175x1n5{background:linear-gradient(135deg,#667eea,#764ba2);color:#fff;border:none}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-title.svelte-175x1n5,.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-subtitle.svelte-175x1n5{color:#fffc}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#fff}.value-box.bg-gradient-indigo-purple.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#ffffffe6}.value-box.success.svelte-175x1n5.svelte-175x1n5{background:#f0fdf4;border-color:#bbf7d0}.value-box.success.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#065f46}.value-box.success.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#059669}.value-box.warning.svelte-175x1n5.svelte-175x1n5{background:#fffbeb;border-color:#fed7aa}.value-box.warning.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#92400e}.value-box.warning.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#d97706}.value-box.danger.svelte-175x1n5.svelte-175x1n5{background:#fef2f2;border-color:#fecaca}.value-box.danger.svelte-175x1n5 .value-box-value.svelte-175x1n5{color:#991b1b}.value-box.danger.svelte-175x1n5 .value-box-change.svelte-175x1n5{color:#dc2626}@media (max-width: 640px){.value-box.svelte-175x1n5.svelte-175x1n5{padding:1rem;min-height:100px}.value-box-value.svelte-175x1n5.svelte-175x1n5{font-size:1.5rem}}table .value-box{min-height:auto;padding:.75rem;margin:.25rem 0}table .value-box-value{font-size:1.25rem}.events-container.svelte-11m3hns.svelte-11m3hns{border:1px solid #e5e7eb;border-radius:.5rem;background:#fff;padding:1rem;margin-bottom:1rem}.events-title.svelte-11m3hns.svelte-11m3hns{font-size:1.25rem;font-weight:600;color:#111827;margin:0 0 1rem;padding-bottom:.5rem;border-bottom:2px solid #e5e7eb}.stats-header.svelte-11m3hns.svelte-11m3hns{display:flex;justify-content:space-between;align-items:center;padding:.5rem .75rem;margin-bottom:1rem;border-radius:.375rem;font-size:.875rem;border:1px solid #e5e7eb}.stats-header.live.svelte-11m3hns.svelte-11m3hns{background:#f0fdf4;border-color:#bbf7d0}.stats-header.recent.svelte-11m3hns.svelte-11m3hns{background:#fffbeb;border-color:#fed7aa}.stats-header.stale.svelte-11m3hns.svelte-11m3hns{background:#fef2f2;border-color:#fecaca}.stats-indicator.svelte-11m3hns.svelte-11m3hns{display:flex;align-items:center;gap:.5rem}.live-dot.svelte-11m3hns.svelte-11m3hns{width:10px;height:10px;border-radius:50%;background:#10b981;box-shadow:0 0 0 2px #10b98133;transition:all .3s ease}.stats-header.live.svelte-11m3hns .live-dot.svelte-11m3hns{background:#10b981;box-shadow:0 0 0 2px #10b9814d,0 0 8px #10b98166;animation:svelte-11m3hns-livePulse 2s infinite}.stats-header.recent.svelte-11m3hns .live-dot.svelte-11m3hns{background:#f59e0b;box-shadow:0 0 0 2px #f59e0b33}.stats-header.stale.svelte-11m3hns .live-dot.svelte-11m3hns{background:#ef4444;box-shadow:0 0 0 2px #ef444433}.stats-header.finished.svelte-11m3hns.svelte-11m3hns{background:#f0f9ff;border-color:#bae6fd}.stats-header.finished.svelte-11m3hns .live-dot.svelte-11m3hns{background:#0ea5e9;box-shadow:0 0 0 2px #0ea5e933}.status-text.svelte-11m3hns.svelte-11m3hns{font-weight:500;color:#374151}.stats-info.svelte-11m3hns.svelte-11m3hns{display:flex;gap:1rem;font-size:.8125rem;color:#6b7280}.stat-item.svelte-11m3hns.svelte-11m3hns{white-space:nowrap}.no-events.svelte-11m3hns.svelte-11m3hns{text-align:center;padding:2rem;color:#6b7280;font-style:italic}.events-timeline.svelte-11m3hns.svelte-11m3hns{position:relative;padding-left:2rem}.events-timeline.svelte-11m3hns.svelte-11m3hns:before{content:"";position:absolute;left:.75rem;top:0;bottom:0;width:2px;background:linear-gradient(to bottom,#3b82f6,#e5e7eb)}.event-item.svelte-11m3hns.svelte-11m3hns{position:relative;margin-bottom:1.5rem;padding-left:1rem}.event-item.svelte-11m3hns.svelte-11m3hns:last-child{margin-bottom:0}.event-marker.svelte-11m3hns.svelte-11m3hns{position:absolute;left:-1.525rem;top:0;width:.75rem;height:.75rem;border-radius:50%;background:#3b82f6;border:2px solid white;box-shadow:0 0 0 2px #3b82f6;z-index:1}.event-item.latest.svelte-11m3hns .event-marker.svelte-11m3hns{background:#10b981;box-shadow:0 0 0 2px #10b9814d;animation:svelte-11m3hns-markerPulse 2s infinite}@keyframes svelte-11m3hns-livePulse{0%,to{transform:scale(1);box-shadow:0 0 0 2px #10b9814d,0 0 8px #10b98166}50%{transform:scale(1.1);box-shadow:0 0 0 4px #10b98133,0 0 12px #10b98199}}@keyframes svelte-11m3hns-markerPulse{0%,to{box-shadow:0 0 0 2px #10b9814d}50%{box-shadow:0 0 0 4px #10b98180}}.event-content.svelte-11m3hns.svelte-11m3hns{background:#f9fafb;border:1px solid #e5e7eb;border-radius:.375rem;padding:.75rem;box-shadow:0 1px 2px #0000000d}.event-item.latest.svelte-11m3hns .event-content.svelte-11m3hns{background:#f0f9ff;border-color:#3b82f6}.event-item.theme-success.svelte-11m3hns .event-content.svelte-11m3hns{background:#f0fdf4;border-color:#bbf7d0}.event-item.theme-success.svelte-11m3hns .event-marker.svelte-11m3hns{background:#10b981;box-shadow:0 0 0 2px #10b981}.event-item.theme-error.svelte-11m3hns .event-content.svelte-11m3hns{background:#fef2f2;border-color:#fecaca}.event-item.theme-error.svelte-11m3hns .event-marker.svelte-11m3hns{background:#ef4444;box-shadow:0 0 0 2px #ef4444}.event-item.theme-warning.svelte-11m3hns .event-content.svelte-11m3hns{background:#fffbeb;border-color:#fed7aa}.event-item.theme-warning.svelte-11m3hns .event-marker.svelte-11m3hns{background:#f59e0b;box-shadow:0 0 0 2px #f59e0b}.event-item.theme-info.svelte-11m3hns .event-content.svelte-11m3hns{background:#eff6ff;border-color:#bfdbfe}.event-item.theme-info.svelte-11m3hns .event-marker.svelte-11m3hns{background:#3b82f6;box-shadow:0 0 0 2px #3b82f6}.event-item.theme-tool_call.svelte-11m3hns .event-content.svelte-11m3hns{background:#f3e8ff;border-color:#c4b5fd}.event-item.theme-tool_call.svelte-11m3hns .event-marker.svelte-11m3hns{background:#8b5cf6;box-shadow:0 0 0 2px #8b5cf6}.event-item.theme-ai_response.svelte-11m3hns .event-content.svelte-11m3hns{background:#fdf4ff;border-color:#e9d5ff}.event-item.theme-ai_response.svelte-11m3hns .event-marker.svelte-11m3hns{background:#a855f7;box-shadow:0 0 0 2px #a855f7}.event-item.priority-high.svelte-11m3hns.svelte-11m3hns{border-left:4px solid #f59e0b}.event-item.priority-critical.svelte-11m3hns.svelte-11m3hns{border-left:4px solid #ef4444}.event-meta.svelte-11m3hns.svelte-11m3hns{display:flex;justify-content:space-between;align-items:center;margin-bottom:.5rem;padding-bottom:.5rem;border-bottom:1px solid #e5e7eb;font-size:.75rem;color:#6b7280}.event-time.svelte-11m3hns.svelte-11m3hns{font-weight:500}.event-id.svelte-11m3hns.svelte-11m3hns{font-family:Monaco,Menlo,Ubuntu Mono,monospace;opacity:.7}.event-metadata.svelte-11m3hns.svelte-11m3hns{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:.5rem}.event-payloads.svelte-11m3hns.svelte-11m3hns{margin-top:1rem;border-top:1px solid #e5e7eb;padding-top:.75rem}.payload-section.svelte-11m3hns.svelte-11m3hns{margin-bottom:.75rem;border:1px solid #e5e7eb;border-radius:.375rem;overflow:hidden}.payload-section.svelte-11m3hns.svelte-11m3hns:last-child{margin-bottom:0}.payload-header.svelte-11m3hns.svelte-11m3hns{display:flex;justify-content:space-between;align-items:center;padding:.75rem 1rem;background:#f9fafb;cursor:pointer;-webkit-user-select:none;user-select:none;border-bottom:1px solid #e5e7eb;font-weight:500}.payload-header.svelte-11m3hns.svelte-11m3hns:hover{background:#f3f4f6}.payload-title.svelte-11m3hns.svelte-11m3hns{font-size:.875rem;color:#374151}.payload-type.svelte-11m3hns.svelte-11m3hns{font-size:.75rem;color:#6b7280;background:#e5e7eb;padding:.125rem .5rem;border-radius:.25rem;text-transform:uppercase;letter-spacing:.025em}.payload-content.svelte-11m3hns.svelte-11m3hns{padding:1rem;background:#fff;font-size:inherit;line-height:inherit;color:inherit}.payload-content.svelte-11m3hns>*{margin-bottom:0}.payload-content.svelte-11m3hns>*:not(:last-child){margin-bottom:1rem}.payload-content.svelte-11m3hns pre[data-component=pythonCode]{margin:0;overflow-x:auto}.payload-content.svelte-11m3hns pre[data-component=pythonCode] code{display:block}.payload-content.svelte-11m3hns code:not(pre code){font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.875rem;background:#f1f5f9;padding:.125rem .25rem;border-radius:.25rem}.event-field.svelte-11m3hns.svelte-11m3hns{display:flex;flex-direction:column;gap:.125rem}.field-key.svelte-11m3hns.svelte-11m3hns{font-size:.75rem;font-weight:500;color:#6b7280;text-transform:uppercase;letter-spacing:.025em}.field-value.svelte-11m3hns.svelte-11m3hns{font-size:.875rem;font-weight:400;color:#111827;word-break:break-word;display:inline-block;width:auto}.field-value.timestamp.svelte-11m3hns.svelte-11m3hns{font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.8125rem;color:#6366f1}.field-value.number.svelte-11m3hns.svelte-11m3hns{font-family:Monaco,Menlo,Ubuntu Mono,monospace;color:#059669}.field-value.status.svelte-11m3hns.svelte-11m3hns,.field-value.status-success.svelte-11m3hns.svelte-11m3hns,.field-value.status-error.svelte-11m3hns.svelte-11m3hns,.field-value.status-warning.svelte-11m3hns.svelte-11m3hns,.field-value.status-milestone.svelte-11m3hns.svelte-11m3hns,.field-value.status-completed.svelte-11m3hns.svelte-11m3hns,.field-value.status-finished.svelte-11m3hns.svelte-11m3hns{font-weight:500;text-transform:uppercase;font-size:.75rem;letter-spacing:.025em;padding:.125rem .375rem;border-radius:.25rem;display:inline-flex!important;align-items:center;justify-content:center;background:#f3f4f6;color:#374151;width:fit-content!important;max-width:fit-content!important;min-width:auto!important;flex-shrink:0;white-space:nowrap}.field-value.status-success.svelte-11m3hns.svelte-11m3hns{color:#059669;background:#d1fae5}.field-value.status-error.svelte-11m3hns.svelte-11m3hns{color:#dc2626;background:#fee2e2}.field-value.status-warning.svelte-11m3hns.svelte-11m3hns{color:#d97706;background:#fef3c7}.field-value.status-milestone.svelte-11m3hns.svelte-11m3hns{color:#7c3aed;background:#ede9fe}.field-value.status-completed.svelte-11m3hns.svelte-11m3hns{color:#059669;background:#d1fae5}.field-value.status-finished.svelte-11m3hns.svelte-11m3hns{color:#0ea5e9;background:#e0f2fe}@media (max-width: 640px){.events-container.svelte-11m3hns.svelte-11m3hns{padding:.75rem}.events-timeline.svelte-11m3hns.svelte-11m3hns{padding-left:1.5rem}.stats-info.svelte-11m3hns.svelte-11m3hns{flex-direction:column;gap:.25rem;align-items:flex-end}.event-metadata.svelte-11m3hns.svelte-11m3hns{grid-template-columns:1fr;gap:.375rem}.event-field.svelte-11m3hns.svelte-11m3hns{flex-direction:row;align-items:flex-start;gap:.5rem}.field-key.svelte-11m3hns.svelte-11m3hns{min-width:80px;flex-shrink:0}}table .events-container{margin:.25rem 0;border:none;background:transparent;padding:.5rem}table .events-timeline{padding-left:1rem}table .event-content{padding:.5rem}table .stats-header{font-size:.75rem;padding:.375rem .5rem}.json-viewer.svelte-1b8g4ty.svelte-1b8g4ty{border:1px solid #e5e7eb;border-radius:.375rem;background:#f9fafb;margin:.5rem 0;overflow:hidden}.json-header.svelte-1b8g4ty.svelte-1b8g4ty{display:flex;justify-content:space-between;align-items:center;padding:.5rem .75rem;background:#f3f4f6;border-bottom:1px solid #e5e7eb;font-size:.875rem;font-weight:500}.collapse-button.svelte-1b8g4ty.svelte-1b8g4ty{display:flex;align-items:center;gap:.5rem;background:none;border:none;color:#374151;cursor:pointer;font-size:.875rem;font-weight:500}.collapse-button.svelte-1b8g4ty.svelte-1b8g4ty:hover{color:#111827}.collapse-icon.svelte-1b8g4ty.svelte-1b8g4ty{transition:transform .2s ease;font-size:.75rem}.collapse-icon.collapsed.svelte-1b8g4ty.svelte-1b8g4ty{transform:rotate(-90deg)}.json-label.svelte-1b8g4ty.svelte-1b8g4ty{color:#374151;font-weight:500}.copy-button.svelte-1b8g4ty.svelte-1b8g4ty{background:#3b82f6;color:#fff;border:none;border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;cursor:pointer;transition:all .2s ease}.copy-button.svelte-1b8g4ty.svelte-1b8g4ty:hover{background:#2563eb}.copy-button.success.svelte-1b8g4ty.svelte-1b8g4ty{background:#10b981}.json-content.svelte-1b8g4ty.svelte-1b8g4ty{overflow:auto;max-height:400px}.json-code.svelte-1b8g4ty.svelte-1b8g4ty{margin:0;padding:0;background:transparent;border:none;overflow:visible}.json-code.svelte-1b8g4ty code.svelte-1b8g4ty{display:block;padding:1rem;font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.8125rem;line-height:1.5;background:transparent;color:#374151;white-space:pre-wrap;word-break:break-word;border:none}@media (max-width: 640px){.json-header.svelte-1b8g4ty.svelte-1b8g4ty{padding:.375rem .5rem;font-size:.8125rem}.json-code.svelte-1b8g4ty.svelte-1b8g4ty{padding:.75rem .5rem;font-size:.75rem}.copy-button.svelte-1b8g4ty.svelte-1b8g4ty{padding:.1875rem .375rem;font-size:.6875rem}}table .json-viewer{margin:.25rem 0;font-size:.75rem}table .json-content{max-height:200px}table .json-code{padding:.5rem;font-size:.6875rem}.yaml-viewer.svelte-yn00t6.svelte-yn00t6{border:1px solid #e5e7eb;border-radius:.375rem;background:#f9fafb;margin:.5rem 0;overflow:hidden}.yaml-header.svelte-yn00t6.svelte-yn00t6{display:flex;justify-content:space-between;align-items:center;padding:.5rem .75rem;background:#f3f4f6;border-bottom:1px solid #e5e7eb;font-size:.875rem;font-weight:500}.collapse-button.svelte-yn00t6.svelte-yn00t6{display:flex;align-items:center;gap:.5rem;background:none;border:none;color:#374151;cursor:pointer;font-size:.875rem;font-weight:500}.collapse-button.svelte-yn00t6.svelte-yn00t6:hover{color:#111827}.collapse-icon.svelte-yn00t6.svelte-yn00t6{transition:transform .2s ease;font-size:.75rem}.collapse-icon.collapsed.svelte-yn00t6.svelte-yn00t6{transform:rotate(-90deg)}.yaml-label.svelte-yn00t6.svelte-yn00t6{color:#374151;font-weight:500}.copy-button.svelte-yn00t6.svelte-yn00t6{background:#3b82f6;color:#fff;border:none;border-radius:.25rem;padding:.25rem .5rem;font-size:.75rem;cursor:pointer;transition:all .2s ease}.copy-button.svelte-yn00t6.svelte-yn00t6:hover{background:#2563eb}.copy-button.success.svelte-yn00t6.svelte-yn00t6{background:#10b981}.yaml-content.svelte-yn00t6.svelte-yn00t6{overflow:auto;max-height:400px}.yaml-code.svelte-yn00t6.svelte-yn00t6{margin:0;padding:0;background:transparent;border:none;overflow:visible}.yaml-code.svelte-yn00t6 code.svelte-yn00t6{display:block;padding:1rem;font-family:Monaco,Menlo,Ubuntu Mono,monospace;font-size:.8125rem;line-height:1.6;background:transparent;color:#374151;white-space:pre-wrap;word-break:break-word;border:none}@media (max-width: 640px){.yaml-header.svelte-yn00t6.svelte-yn00t6{padding:.375rem .5rem;font-size:.8125rem}.yaml-code.svelte-yn00t6.svelte-yn00t6{padding:.75rem .5rem;font-size:.75rem}.copy-button.svelte-yn00t6.svelte-yn00t6{padding:.1875rem .375rem;font-size:.6875rem}}table .yaml-viewer{margin:.25rem 0;font-size:.75rem}table .yaml-content{max-height:200px}table .yaml-code{padding:.5rem;font-size:.6875rem}td.svelte-gl9h79{text-align:left}td.labelColumn.svelte-gl9h79{text-align:right;background-color:var(--lt-grey);font-weight:700;width:12%;white-space:nowrap}.tableContainer.svelte-q3hq57{overflow:auto}th.svelte-q3hq57{position:sticky;top:-1px;z-index:2;white-space:nowrap;background:var(--white)}.mainContainer.svelte-mqeomk{max-width:110rem}main.svelte-mqeomk{flex:0 1 auto;max-width:100rem;padding:1.5rem}@media (min-width: 60rem){main.svelte-mqeomk{margin-left:var(--aside-width)}}.embed main{margin:0 auto;min-width:80%}.modal.svelte-1hhf5ym{align-items:center;background:#00000080;bottom:0;cursor:pointer;display:flex;height:100%;justify-content:center;left:0;overflow:hidden;position:fixed;right:0;top:0;width:100%;z-index:100}.modalContainer>*{background-color:#fff;border-radius:5px;cursor:default;flex:0 1 auto;padding:1rem;position:relative}.modal img{max-height:80vh!important}.cancelButton.svelte-1hhf5ym{color:#fff;cursor:pointer;font-size:2rem;position:absolute;right:1rem;top:1rem}.cancelButton.svelte-1hhf5ym:hover{color:var(--blue)}.nav.svelte-1kdpgko.svelte-1kdpgko{border-radius:0 0 5px;display:none;margin:0;top:0}ul.navList.svelte-1kdpgko.svelte-1kdpgko{list-style-type:none}ul.navList.svelte-1kdpgko ul.svelte-1kdpgko{margin:.5rem 1rem 2rem}.navList.svelte-1kdpgko li.svelte-1kdpgko{display:block;margin:0}.navItem.svelte-1kdpgko li.svelte-1kdpgko:hover{color:var(--blue)}.pageId.svelte-1kdpgko.svelte-1kdpgko{display:block;border-bottom:1px solid var(--grey);padding:0 .5rem;margin-bottom:1rem}@media (min-width: 60rem){.nav.svelte-1kdpgko.svelte-1kdpgko{display:block}ul.navList.svelte-1kdpgko.svelte-1kdpgko{text-align:left}.navList.svelte-1kdpgko li.svelte-1kdpgko{display:block;margin:.5rem 0}}.container.svelte-teyund{width:100%;display:flex;flex-direction:column;position:relative}
@@ -12,6 +12,7 @@ from .basic import (
12
12
  from .card import MetaflowCardComponent, with_default_component_id
13
13
  from .convert_to_native_type import TaskToDict, _full_classname
14
14
  from .renderer_tools import render_safely
15
+ from .json_viewer import JSONViewer as _JSONViewer, YAMLViewer as _YAMLViewer
15
16
  import uuid
16
17
  import inspect
17
18
 
@@ -1099,3 +1100,343 @@ class PythonCode(UserComponent):
1099
1100
  _code_component = PythonCodeComponent(self._code_string)
1100
1101
  _code_component.component_id = self.component_id
1101
1102
  return _code_component.render()
1103
+
1104
+
1105
+ class EventsTimeline(UserComponent):
1106
+ """
1107
+ An events timeline component for displaying structured log messages in real-time.
1108
+
1109
+ This component displays events in a timeline format with the latest events at the top.
1110
+ Each event can contain structured data including other UserComponents for rich display.
1111
+
1112
+ Example: Basic usage
1113
+ ```python
1114
+ @card
1115
+ @step
1116
+ def my_step(self):
1117
+ from metaflow.cards import EventsTimeline
1118
+ from metaflow import current
1119
+
1120
+ # Create an events component
1121
+ events = EventsTimeline(title="Processing Events")
1122
+ current.card.append(events)
1123
+
1124
+ # Add events during processing
1125
+ for i in range(10):
1126
+ events.update(
1127
+ event_data={
1128
+ "timestamp": datetime.now().isoformat(),
1129
+ "event_type": "processing",
1130
+ "item_id": i,
1131
+ "status": "completed",
1132
+ "duration_ms": random.randint(100, 500)
1133
+ }
1134
+ )
1135
+ time.sleep(1)
1136
+ ```
1137
+
1138
+ Example: With styling and rich components
1139
+ ```python
1140
+ from metaflow.cards import EventsTimeline, Markdown, PythonCode
1141
+
1142
+ events = EventsTimeline(title="Agent Actions")
1143
+ current.card.append(events)
1144
+
1145
+ # Event with styling
1146
+ events.update(
1147
+ event_data={
1148
+ "action": "tool_call",
1149
+ "function": "get_weather",
1150
+ "result": "Success"
1151
+ },
1152
+ style_theme="success"
1153
+ )
1154
+
1155
+ # Event with rich components
1156
+ events.update(
1157
+ event_data={
1158
+ "action": "code_execution",
1159
+ "status": "completed"
1160
+ },
1161
+ payloads={
1162
+ "code": PythonCode(code_string="print('Hello World')"),
1163
+ "notes": Markdown("**Important**: This ran successfully")
1164
+ },
1165
+ style_theme="info"
1166
+ )
1167
+ ```
1168
+
1169
+ Parameters
1170
+ ----------
1171
+ title : str, optional
1172
+ Title for the events timeline.
1173
+ max_events : int, default 100
1174
+ Maximum number of events to display. Older events are removed from display
1175
+ but total count is still tracked. Stats and relative time display are always enabled.
1176
+ """
1177
+
1178
+ type = "eventsTimeline"
1179
+
1180
+ REALTIME_UPDATABLE = True
1181
+
1182
+ # Valid style themes
1183
+ VALID_THEMES = {
1184
+ "default",
1185
+ "success",
1186
+ "warning",
1187
+ "error",
1188
+ "info",
1189
+ "primary",
1190
+ "secondary",
1191
+ "tool_call",
1192
+ "ai_response",
1193
+ }
1194
+
1195
+ def __init__(
1196
+ self,
1197
+ title: Optional[str] = None,
1198
+ max_events: int = 100,
1199
+ ):
1200
+ self._title = title
1201
+ self._max_events = max_events
1202
+ self._events = []
1203
+
1204
+ # Metadata tracking
1205
+ self._total_events_count = 0
1206
+ self._first_event_time = None
1207
+ self._last_update_time = None
1208
+ self._finished = False
1209
+
1210
+ def update(
1211
+ self,
1212
+ event_data: dict,
1213
+ style_theme: Optional[str] = None,
1214
+ priority: Optional[str] = None,
1215
+ payloads: Optional[dict] = None,
1216
+ finished: Optional[bool] = None,
1217
+ ):
1218
+ """
1219
+ Add a new event to the timeline.
1220
+
1221
+ Parameters
1222
+ ----------
1223
+ event_data : dict
1224
+ Basic event metadata (strings, numbers, simple values only).
1225
+ This appears in the main event display area.
1226
+ style_theme : str, optional
1227
+ Visual theme for this event. Valid values: 'default', 'success', 'warning',
1228
+ 'error', 'info', 'primary', 'secondary', 'tool_call', 'ai_response'.
1229
+ priority : str, optional
1230
+ Priority level for the event ('low', 'normal', 'high', 'critical').
1231
+ Affects visual prominence.
1232
+ payloads : dict, optional
1233
+ Rich payload components that will be displayed in collapsible sections.
1234
+ Values must be UserComponent instances: ValueBox, Image, Markdown,
1235
+ Artifact, JSONViewer, YAMLViewer. VegaChart is not supported inside EventsTimeline.
1236
+ finished : bool, optional
1237
+ Mark the timeline as finished. When True, the status indicator will show
1238
+ "Finished" in the header.
1239
+ """
1240
+ import time
1241
+
1242
+ # Validate style_theme
1243
+ if style_theme is not None and style_theme not in self.VALID_THEMES:
1244
+ import re
1245
+
1246
+ if not re.match(r"^[a-zA-Z][a-zA-Z0-9_-]*$", style_theme):
1247
+ raise ValueError(
1248
+ f"Invalid style_theme '{style_theme}'. Must be a valid CSS class name."
1249
+ )
1250
+
1251
+ # Validate payloads contain only allowed UserComponents
1252
+ if payloads is not None:
1253
+ allowed_components = (
1254
+ ValueBox,
1255
+ Image,
1256
+ Markdown,
1257
+ Artifact,
1258
+ PythonCode,
1259
+ _JSONViewer,
1260
+ _YAMLViewer,
1261
+ )
1262
+ for key, payload in payloads.items():
1263
+ if not isinstance(payload, allowed_components):
1264
+ raise TypeError(
1265
+ f"Payload '{key}' must be one of: ValueBox, Image, Markdown, "
1266
+ f"Artifact, JSONViewer, YAMLViewer. Got {type(payload).__name__}"
1267
+ )
1268
+
1269
+ # Add timestamp if not provided
1270
+ if "timestamp" not in event_data:
1271
+ event_data["timestamp"] = time.time()
1272
+
1273
+ # Create event object with metadata and payloads
1274
+ event = {
1275
+ "metadata": event_data,
1276
+ "payloads": payloads or {},
1277
+ "event_id": f"event_{self._total_events_count}",
1278
+ "received_at": time.time(),
1279
+ }
1280
+
1281
+ # Add styling metadata if provided
1282
+ if style_theme is not None:
1283
+ event["style_theme"] = style_theme
1284
+ if priority is not None:
1285
+ event["priority"] = priority
1286
+
1287
+ # Update metadata
1288
+ self._total_events_count += 1
1289
+ self._last_update_time = time.time()
1290
+ if self._first_event_time is None:
1291
+ self._first_event_time = time.time()
1292
+
1293
+ # Update finished status if provided
1294
+ if finished is not None:
1295
+ self._finished = finished
1296
+
1297
+ # Add the event to the beginning of the list (latest first)
1298
+ self._events.insert(0, event)
1299
+
1300
+ # Trim displayed events if we exceed max_events
1301
+ if len(self._events) > self._max_events:
1302
+ self._events = self._events[: self._max_events]
1303
+
1304
+ def get_stats(self) -> dict:
1305
+ """
1306
+ Get timeline statistics.
1307
+
1308
+ Returns
1309
+ -------
1310
+ dict
1311
+ Statistics including total events, display count, timing info, etc.
1312
+ """
1313
+ import time
1314
+
1315
+ current_time = time.time()
1316
+
1317
+ stats = {
1318
+ "total_events": self._total_events_count,
1319
+ "displayed_events": len(self._events),
1320
+ "last_update": self._last_update_time,
1321
+ "first_event": self._first_event_time,
1322
+ }
1323
+
1324
+ # seconds_since_last_update removed; UI derives recency from last event timestamp
1325
+
1326
+ # Add finished status
1327
+ stats["finished"] = self._finished
1328
+
1329
+ if self._first_event_time and self._total_events_count > 1:
1330
+ runtime = self._last_update_time - self._first_event_time
1331
+ if runtime > 0:
1332
+ stats["events_per_minute"] = round(
1333
+ (self._total_events_count / runtime) * 60, 1
1334
+ )
1335
+ stats["total_runtime_seconds"] = round(runtime, 1)
1336
+
1337
+ return stats
1338
+
1339
+ def _render_subcomponents(self):
1340
+ """
1341
+ Render any UserComponents within event payloads.
1342
+ """
1343
+ rendered_events = []
1344
+
1345
+ for event in self._events:
1346
+ rendered_event = dict(event) # Copy event metadata
1347
+
1348
+ # Event metadata should only contain simple values (no components)
1349
+ rendered_event["metadata"] = event["metadata"]
1350
+
1351
+ # Render payload components
1352
+ rendered_payloads = {}
1353
+ for key, payload in event["payloads"].items():
1354
+ if isinstance(payload, MetaflowCardComponent):
1355
+ # Render the component
1356
+ rendered_payloads[key] = payload.render()
1357
+ else:
1358
+ # This shouldn't happen due to validation, but handle gracefully
1359
+ rendered_payloads[key] = str(payload)
1360
+
1361
+ rendered_event["payloads"] = rendered_payloads
1362
+ rendered_events.append(rendered_event)
1363
+
1364
+ return rendered_events
1365
+
1366
+ @with_default_component_id
1367
+ @render_safely
1368
+ def render(self):
1369
+ data = {
1370
+ "type": self.type,
1371
+ "id": self.component_id,
1372
+ "events": self._render_subcomponents(),
1373
+ "config": {
1374
+ "show_stats": True,
1375
+ "show_relative_time": True,
1376
+ "max_events": self._max_events,
1377
+ },
1378
+ }
1379
+
1380
+ if self._title is not None:
1381
+ data["title"] = self._title
1382
+
1383
+ # Always include stats
1384
+ data["stats"] = self.get_stats()
1385
+
1386
+ return data
1387
+
1388
+
1389
+ # Rich viewer components
1390
+ class JSONViewer(_JSONViewer, UserComponent):
1391
+ """
1392
+ A component for displaying JSON data with syntax highlighting and collapsible sections.
1393
+
1394
+ This component provides a rich view of JSON data with proper formatting, syntax highlighting,
1395
+ and the ability to collapse/expand sections for better readability.
1396
+
1397
+ Example:
1398
+ ```python
1399
+ from metaflow.cards import JSONViewer, EventsTimeline
1400
+ from metaflow import current
1401
+
1402
+ # Use in events timeline
1403
+ events = EventsTimeline(title="API Calls")
1404
+ events.update({
1405
+ "action": "api_request",
1406
+ "endpoint": "/users",
1407
+ "payload": JSONViewer({"user_id": 123, "fields": ["name", "email"]})
1408
+ })
1409
+
1410
+ # Use standalone
1411
+ data = {"config": {"debug": True, "timeout": 30}}
1412
+ current.card.append(JSONViewer(data, collapsible=True))
1413
+ ```
1414
+ """
1415
+
1416
+ pass
1417
+
1418
+
1419
+ class YAMLViewer(_YAMLViewer, UserComponent):
1420
+ """
1421
+ A component for displaying YAML data with syntax highlighting and collapsible sections.
1422
+
1423
+ This component provides a rich view of YAML data with proper formatting and syntax highlighting.
1424
+
1425
+ Example:
1426
+ ```python
1427
+ from metaflow.cards import YAMLViewer, EventsTimeline
1428
+ from metaflow import current
1429
+
1430
+ # Use in events timeline
1431
+ events = EventsTimeline(title="Configuration Changes")
1432
+ events.update({
1433
+ "action": "config_update",
1434
+ "config": YAMLViewer({
1435
+ "database": {"host": "localhost", "port": 5432},
1436
+ "features": ["auth", "logging"]
1437
+ })
1438
+ })
1439
+ ```
1440
+ """
1441
+
1442
+ pass
@@ -8,7 +8,9 @@ TypeResolvedObject = namedtuple("TypeResolvedObject", ["data", "is_image", "is_t
8
8
 
9
9
 
10
10
  TIME_FORMAT = "%Y-%m-%d %I:%M:%S %p"
11
- MAX_ARTIFACT_SIZE = 1 # in 1 MB
11
+ # Maximum artifact size to render in cards: 200MB (in bytes)
12
+ # Artifacts larger than this will be skipped during card rendering to avoid memory issues
13
+ MAX_ARTIFACT_SIZE = 256 * 1024 * 1024 # 256 MB = 268435456 bytes
12
14
 
13
15
 
14
16
  def _get_object_size(obj, seen=None):
@@ -44,7 +46,7 @@ def _full_classname(obj):
44
46
 
45
47
 
46
48
  class TaskToDict:
47
- def __init__(self, only_repr=False, runtime=False):
49
+ def __init__(self, only_repr=False, runtime=False, max_artifact_size=None):
48
50
  # this dictionary holds all the supported functions
49
51
  import reprlib
50
52
  import pprint
@@ -61,6 +63,10 @@ class TaskToDict:
61
63
  self._repr = r
62
64
  self._runtime = runtime
63
65
  self._only_repr = only_repr
66
+ # Use the global MAX_ARTIFACT_SIZE constant if not specified
67
+ self._max_artifact_size = (
68
+ max_artifact_size if max_artifact_size is not None else MAX_ARTIFACT_SIZE
69
+ )
64
70
  self._supported_types = {
65
71
  "tuple": self._parse_tuple,
66
72
  "NoneType": self._parse_nonetype,
@@ -110,6 +116,19 @@ class TaskToDict:
110
116
  task_data_dict = {}
111
117
  type_inferred_objects = {"images": {}, "tables": {}}
112
118
  for data in task:
119
+ # Check if artifact size exceeds the maximum allowed size
120
+ if data.size > self._max_artifact_size:
121
+ # Skip artifacts that are too large
122
+ task_data_dict[data.id] = dict(
123
+ type="skipped",
124
+ data=f"<artifact too large: {data.size} bytes, max: {self._max_artifact_size} bytes>",
125
+ large_object=True,
126
+ supported_type=False,
127
+ only_repr=self._only_repr,
128
+ name=data.id,
129
+ )
130
+ continue
131
+
113
132
  try:
114
133
  data_object = data.data
115
134
  task_data_dict[data.id] = self._convert_to_native_type(data_object)
@@ -241,7 +260,8 @@ class TaskToDict:
241
260
  supported_type = True
242
261
  type_parsing_func = self._supported_types[obj_type_name]
243
262
  data_obj = type_parsing_func(data_object)
244
- if _get_object_size(data_obj) * 1e-6 > MAX_ARTIFACT_SIZE:
263
+ # Secondary check: if the in-memory object size exceeds our limit, use repr instead
264
+ if _get_object_size(data_obj) > self._max_artifact_size:
245
265
  data_obj = rep.repr(data_obj)
246
266
  large_object = True
247
267
  else: