Skip to content

Commit 0eb3974

Browse files
committed
fix: correct end_nanos accounting for async model calls
This at least fixes the block timestamps for async model calls. i don’t think it’s possible to do this generally (at least with my understanding of python futures), because the pdl_lazy logic obscures the original asyncio.Future… but this future is available at the point of fire for the async model calls… so i’ve fixed that part. It’s imperfect, because e.g. an outer Text block… doesn’t know that there are Futures under the hood. but still this seems like an improvement over what we had. and that might be something we can patch over in the UI. This includes said patch to the UI (see src/view/timeline/model.ts, the comment that references #683) Signed-off-by: Nick Mitchell <[email protected]>
1 parent 2d2ae30 commit 0eb3974

File tree

3 files changed

+35
-8
lines changed

3 files changed

+35
-8
lines changed

pdl-live-react/src/view/timeline/model.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,12 +75,25 @@ function computeModelIter(
7575
block,
7676
}
7777

78-
return [
79-
...(ignoreRoot ? [] : [root]),
80-
...childrenOf(block)
81-
.filter(nonNullable)
82-
.flatMap((child) => computeModelIter(child, root)),
83-
].filter(nonNullable)
78+
const childrenModel = childrenOf(block)
79+
.filter(nonNullable)
80+
.flatMap((child) => computeModelIter(child, root))
81+
82+
// Correct for anomalies in the trace where a child may have an
83+
// earlier end timestamp than its children. See
84+
// https://github.com/IBM/prompt-declaration-language/pull/683
85+
if (root) {
86+
const maxEnd = childrenModel.reduce(
87+
(maxEnd, child) => Math.max(maxEnd, child.block.pdl__timing.end_nanos),
88+
0,
89+
)
90+
root.block.pdl__timing.end_nanos = Math.max(
91+
root.block.pdl__timing.end_nanos,
92+
maxEnd,
93+
)
94+
}
95+
96+
return [...(ignoreRoot ? [] : [root]), ...childrenModel].filter(nonNullable)
8497
}
8598

8699
export function childrenOf(block: NonScalarPdlBlock) {

src/pdl/pdl_dumper.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ def block_to_dict( # noqa: C901
9797
context = block.context
9898
if len(context) > 0:
9999
d["context"] = context
100-
if block.pdl__timing is not None:
101-
d["pdl__timing"] = timing_to_dict(block.pdl__timing)
102100
if block.description is not None:
103101
d["description"] = block.description
104102
if block.role is not None:
@@ -239,6 +237,12 @@ def block_to_dict( # noqa: C901
239237
# d["location"] = location_to_dict(block.location)
240238
if block.fallback is not None:
241239
d["fallback"] = block_to_dict(block.fallback, json_compatible)
240+
# Warning: remember to update timing here at the end! this ensures
241+
# that any logic that updates timestamps when futures
242+
# finish... has a chance to do its work before we record the
243+
# timestamps to the trace
244+
if block.pdl__timing is not None:
245+
d["pdl__timing"] = timing_to_dict(block.pdl__timing)
242246
return d
243247

244248

src/pdl/pdl_llms.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,16 @@ def generate_text(
100100
pdl_future: PdlLazy[tuple[dict[str, Any], Any]] = PdlConst(future)
101101
message = lazy_apply((lambda x: x[0]), pdl_future)
102102
response = lazy_apply((lambda x: x[1]), pdl_future)
103+
104+
# update the end timestamp when the future is done
105+
def update_end_nanos(future):
106+
import time
107+
108+
if block.pdl__timing is not None:
109+
block.pdl__timing.end_nanos = time.time_ns()
110+
111+
future.add_done_callback(update_end_nanos)
112+
103113
return message, response
104114

105115
@staticmethod

0 commit comments

Comments
 (0)