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 +3 -0
- metaflow/parameters.py +4 -0
- metaflow/plugins/argo/argo_workflows.py +6 -7
- metaflow/plugins/cards/card_modules/basic.py +14 -4
- metaflow/plugins/cards/card_modules/bundle.css +1 -1
- metaflow/plugins/cards/card_modules/components.py +341 -0
- metaflow/plugins/cards/card_modules/convert_to_native_type.py +23 -3
- metaflow/plugins/cards/card_modules/json_viewer.py +232 -0
- metaflow/plugins/cards/card_modules/main.js +54 -39
- metaflow/plugins/datatools/s3/s3op.py +14 -2
- metaflow/runner/click_api.py +12 -0
- metaflow/version.py +1 -1
- {metaflow-2.18.9.data → metaflow-2.18.11.data}/data/share/metaflow/devtools/Tiltfile +1 -0
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/METADATA +2 -2
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/RECORD +21 -20
- {metaflow-2.18.9.data → metaflow-2.18.11.data}/data/share/metaflow/devtools/Makefile +0 -0
- {metaflow-2.18.9.data → metaflow-2.18.11.data}/data/share/metaflow/devtools/pick_services.sh +0 -0
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/WHEEL +0 -0
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/entry_points.txt +0 -0
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/licenses/LICENSE +0 -0
- {metaflow-2.18.9.dist-info → metaflow-2.18.11.dist-info}/top_level.txt +0 -0
metaflow/cards.py
CHANGED
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,
|
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(
|
398
|
-
self.
|
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
|
-
|
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
|
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:
|