Skip to content

Commit 39011df

Browse files
authored
Merge branch 'main' into kenli/cp-shape-optimization
2 parents ab5a570 + 2677b7c commit 39011df

13 files changed

Lines changed: 223 additions & 75 deletions

File tree

.github/workflows/ai-review.yml

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,9 @@ jobs:
377377
import json, os, pathlib
378378
gw = os.environ['GATEWAY_BASE_URL'].rstrip('/')
379379
model = os.environ.get('MODEL') or 'claude-opus-4-1'
380-
claude_maintainer_model = os.environ.get('CLAUDE_MAINTAINER_MODEL') or 'claude-opus-4-8'
380+
claude_maintainer_model = os.environ.get('CLAUDE_MAINTAINER_MODEL') or model
381381
codex_maintainer_model = os.environ.get('CODEX_MAINTAINER_MODEL') or 'gpt-5-codex'
382-
disprove_model = os.environ.get('DISPROVE_MODEL') or 'gpt-5.6-sol'
382+
disprove_model = os.environ.get('DISPROVE_MODEL') or 'gpt-5-6-sol'
383383
cfg = {
384384
'providers': {
385385
'gateway': {
@@ -407,6 +407,39 @@ jobs:
407407
pathlib.Path.home().joinpath('.omnigent', 'config.yaml').write_text(json.dumps(cfg, indent=2))
408408
"
409409
410+
- name: Materialize reviewer model config
411+
if: steps.creds.outputs.available == 'true'
412+
env:
413+
CLAUDE_MAINTAINER_MODEL: ${{ vars.CLAUDE_MAINTAINER_MODEL }}
414+
CODEX_MAINTAINER_MODEL: ${{ vars.CODEX_MAINTAINER_MODEL }}
415+
DISPROVE_MODEL: ${{ vars.DISPROVE_MODEL }}
416+
MODEL: ${{ vars.MODEL }}
417+
run: |
418+
set -euo pipefail
419+
python3 -u <<'PYEOF'
420+
import os
421+
import pathlib
422+
import yaml
423+
424+
model = os.environ.get("MODEL") or "claude-opus-4-1"
425+
replacements = {
426+
"default": model,
427+
"maintainer-claude": os.environ.get("CLAUDE_MAINTAINER_MODEL") or model,
428+
"maintainer-codex": os.environ.get("CODEX_MAINTAINER_MODEL") or "gpt-5-codex",
429+
"disprove": os.environ.get("DISPROVE_MODEL") or "gpt-5-6-sol",
430+
}
431+
432+
for path in pathlib.Path(".github/omnigent/reviewer").rglob("config.yaml"):
433+
cfg = yaml.safe_load(path.read_text())
434+
executor = cfg.get("executor", {})
435+
old_model = executor.get("model")
436+
if old_model in replacements:
437+
executor["model"] = replacements[old_model]
438+
path.write_text(yaml.safe_dump(cfg, sort_keys=False))
439+
440+
print("Materialized AI reviewer model aliases for CI runtime.")
441+
PYEOF
442+
410443
- name: Collect PR context and build review prompt
411444
if: steps.creds.outputs.available == 'true'
412445
env:
@@ -498,17 +531,38 @@ jobs:
498531
if: steps.creds.outputs.available == 'true'
499532
id: review
500533
env:
534+
GATEWAY_BASE_URL: ${{ secrets.GATEWAY_BASE_URL }}
501535
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
536+
MODEL: ${{ vars.MODEL }}
502537
run: |
503538
set -euo pipefail
504539
prompt=$(cat /tmp/review_prompt.txt)
505-
540+
model="${MODEL:-claude-opus-4-1}"
541+
542+
export ANTHROPIC_AUTH_TOKEN="$LLM_API_KEY"
543+
export ANTHROPIC_BASE_URL="${GATEWAY_BASE_URL%/}/anthropic"
544+
export ANTHROPIC_MODEL="$model"
545+
export ANTHROPIC_DEFAULT_MODEL="$model"
546+
export ANTHROPIC_DEFAULT_OPUS_MODEL="$model"
547+
export ANTHROPIC_DEFAULT_SONNET_MODEL="$model"
548+
export OPENAI_API_KEY="$LLM_API_KEY"
549+
export OPENAI_BASE_URL="${GATEWAY_BASE_URL%/}/openai"
550+
551+
set +e
506552
omnigent run .github/omnigent/reviewer/ \
507553
-p "$prompt" \
508554
--no-session \
509555
2>review-stderr.log \
510-
| tee /tmp/review_output.txt \
511-
|| { echo "::warning::AI review exited non-zero"; cat review-stderr.log; }
556+
| tee /tmp/review_output.txt
557+
review_status="${PIPESTATUS[0]}"
558+
set -e
559+
560+
if [ "$review_status" -ne 0 ]; then
561+
echo "::warning::AI review exited with status ${review_status}."
562+
if [ -s review-stderr.log ]; then
563+
cat review-stderr.log
564+
fi
565+
fi
512566
513567
python3 -c "
514568
import pathlib
@@ -528,9 +582,10 @@ jobs:
528582
echo "review_text<<${delim}" >> "$GITHUB_OUTPUT"
529583
cat /tmp/review_output.txt >> "$GITHUB_OUTPUT"
530584
echo "${delim}" >> "$GITHUB_OUTPUT"
585+
echo "review_status=${review_status}" >> "$GITHUB_OUTPUT"
531586
532587
- name: Scan review output for secrets before publishing
533-
if: steps.creds.outputs.available == 'true'
588+
if: always() && steps.creds.outputs.available == 'true'
534589
env:
535590
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
536591
run: |
@@ -540,6 +595,21 @@ jobs:
540595
exit 1
541596
fi
542597
598+
- name: Validate review output
599+
if: always() && steps.creds.outputs.available == 'true'
600+
env:
601+
REVIEW_STATUS: ${{ steps.review.outputs.review_status }}
602+
run: |
603+
set -euo pipefail
604+
if [ "${REVIEW_STATUS:-1}" -ne 0 ]; then
605+
echo "::error::AI review exited with status ${REVIEW_STATUS:-unknown}."
606+
exit 1
607+
fi
608+
if [ ! -s /tmp/review_output.txt ]; then
609+
echo "::error::AI review produced no publishable output."
610+
exit 1
611+
fi
612+
543613
- name: Post review comment
544614
if: >-
545615
steps.review.outputs.review_text != '' &&

default-engine/src/executor.rs

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -155,11 +155,9 @@ pub mod tokio {
155155

156156
let fut = Box::pin(async move {
157157
let task_output = task.await;
158-
tokio::task::spawn_blocking(move || {
159-
sender.send(task_output).ok();
160-
})
161-
.await
162-
.unwrap();
158+
// `std::sync::mpsc::Sender::send` never waits for channel capacity, so this
159+
// synchronous handoff is safe to do directly from the async task.
160+
sender.send(task_output).ok();
163161
});
164162

165163
self.send_future(fut);
@@ -255,9 +253,6 @@ pub mod tokio {
255253
impl TaskExecutor for TokioMultiThreadExecutor {
256254
type Guard<'a> = EnterGuard<'a>;
257255

258-
// `block_on` uses `block_in_place`; If concurrent `block_on` calls exceed Tokio's
259-
// `max_blocking_threads`, this can deadlock See:
260-
// https://docs.rs/tokio/latest/tokio/runtime/struct.Builder.html#method.max_blocking_threads
261256
fn block_on<T>(&self, task: T) -> T::Output
262257
where
263258
T: Future + Send + 'static,
@@ -270,11 +265,9 @@ pub mod tokio {
270265

271266
let fut = Box::pin(async move {
272267
let task_output = task.await;
273-
tokio::task::spawn_blocking(move || {
274-
sender.send(task_output).ok();
275-
})
276-
.await
277-
.unwrap();
268+
// `std::sync::mpsc::Sender::send` never waits for channel capacity, so this
269+
// synchronous handoff is safe to do directly from the async task.
270+
sender.send(task_output).ok();
278271
});
279272

280273
// We throw away the handle, but it should continue on.
@@ -414,47 +407,51 @@ pub mod tokio {
414407
}
415408

416409
#[test]
417-
fn test_owned_runtime_small_pool_nested_block_on_deadlocks() {
410+
fn test_owned_runtime_small_blocking_pool_completes_many_block_on_calls() {
418411
use std::sync::Arc;
419412
use std::time::Duration;
420413

421-
// Create a small pool
422414
let executor = Arc::new(
423-
TokioMultiThreadExecutor::new_owned_runtime(Some(1), Some(1))
415+
TokioMultiThreadExecutor::new_owned_runtime(Some(2), Some(1))
424416
.expect("Failed to create executor"),
425417
);
426-
let e1 = executor.clone();
427-
let e2 = executor.clone();
428-
let e3 = executor.clone();
429418

430419
let (tx, rx) = channel::<i32>();
431-
432-
// Spawn a thread to do deeply nested block_on calls
433-
std::thread::spawn(move || {
434-
let result = executor.block_on(async move {
435-
e1.block_on(async move {
436-
e2.block_on(async move {
437-
e3.block_on(async {
420+
let handles = executor.block_on({
421+
let executor = executor.clone();
422+
let tx = tx.clone();
423+
async move {
424+
let mut handles = Vec::new();
425+
for value in 0..8 {
426+
let executor = executor.clone();
427+
let tx = tx.clone();
428+
handles.push(tokio::task::spawn_blocking(move || {
429+
let result = executor.block_on(async move {
438430
tokio::time::sleep(Duration::from_millis(1)).await;
439-
42
440-
})
441-
})
442-
})
443-
});
444-
tx.send(result).ok();
431+
value
432+
});
433+
tx.send(result).ok();
434+
}));
435+
}
436+
handles
437+
}
445438
});
439+
drop(tx);
440+
441+
let mut results = Vec::new();
442+
for _ in 0..handles.len() {
443+
results.push(
444+
rx.recv_timeout(Duration::from_secs(5))
445+
.expect("Timeout - likely deadlock in TokioMultiThreadExecutor::block_on"),
446+
);
447+
}
446448

447-
// With 1 worker thread, 1 blocking thread and 4 nested block_on calls, this should
448-
// deadlock
449-
let timeout = Duration::from_millis(500);
450-
let result = rx.recv_timeout(timeout);
449+
for handle in handles {
450+
executor.block_on(handle).expect("blocking task panicked");
451+
}
451452

452-
// Test passes if we got a timeout (deadlock occurred as expected)
453-
// Test fails if we got a result (no deadlock - unexpected)
454-
assert!(
455-
result.is_err(),
456-
"Expected deadlock with 1 worker thread, 1 blocking thread and 4 nested block_on calls",
457-
);
453+
results.sort_unstable();
454+
assert_eq!(results, (0..8).collect::<Vec<_>>());
458455
}
459456

460457
#[test]

ffi/src/delta_kernel_unity_catalog.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ impl UpdateTableClient for FfiUCCommitClient {
103103

104104
match (self.commit_callback)(self.context, c_commit_request) {
105105
OptionalValue::Some(e) => {
106-
let boxed_str = unsafe { e.into_inner() }; // get the string back into Box<String>
106+
let boxed_str = unsafe { e.into_inner() }; // get the string back into
107+
// Box<String>
107108
let s: String = *boxed_str; // move back onto the stack
108109
Err(unity_catalog_delta_client_api::Error::Generic(s))
109110
}

ffi/src/ffi_tracing.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -925,8 +925,8 @@ mod tests {
925925
}
926926

927927
#[test]
928-
#[ignore] // We cannot run this test if test_enable_log_line_tracing was run before - see comment there,
929-
// however this test works if run individually.
928+
#[ignore] // We cannot run this test if test_enable_log_line_tracing was run before - see
929+
// comment there, however this test works if run individually.
930930
fn test_enable_event_tracing() {
931931
let _lock = TEST_LOCK.lock().unwrap();
932932
setup_events();

kernel/src/action_reconciliation/log_replay.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1033,7 +1033,8 @@ mod tests {
10331033
let (results, actions_count, add_actions) = run_action_reconciliation_test(input_batches)?;
10341034

10351035
// Verify results
1036-
assert_eq!(results.len(), 2); // The third batch should be filtered out since there are no selected actions
1036+
assert_eq!(results.len(), 2); // The third batch should be filtered out since there are no
1037+
// selected actions
10371038
assert_eq!(results[0].selection_vector(), &vec![true]);
10381039
assert_eq!(results[1].selection_vector(), &vec![false, true]);
10391040
assert_eq!(actions_count, 2);

kernel/src/actions/mod.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -325,8 +325,7 @@ impl Default for Format {
325325
Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, IntoStructData,
326326
)]
327327
#[serde(rename_all = "camelCase")]
328-
#[internal_api]
329-
pub(crate) struct Metadata {
328+
pub struct Metadata {
330329
/// Unique identifier for this table
331330
id: String,
332331
/// User-provided identifier for this table
@@ -567,10 +566,9 @@ impl IntoEngineData for Metadata {
567566
// validated by `try_new`, like the JSON-replay path. Otherwise a CRC file could load a malformed
568567
// feature shape that log replay would reject.
569568
#[serde(rename_all = "camelCase", try_from = "ProtocolRaw")]
570-
#[internal_api]
571569
// TODO move to another module so that we disallow constructing this struct without using the
572570
// try_new function.
573-
pub(crate) struct Protocol {
571+
pub struct Protocol {
574572
/// The minimum version of the Delta read protocol that a client must implement
575573
/// in order to correctly read this table
576574
min_reader_version: i32,
@@ -1538,8 +1536,7 @@ pub(crate) struct CheckpointMetadata {
15381536
#[derive(
15391537
Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, IntoStructData, IntoEngineData,
15401538
)]
1541-
#[internal_api]
1542-
pub(crate) struct DomainMetadata {
1539+
pub struct DomainMetadata {
15431540
domain: String,
15441541
configuration: String,
15451542
removed: bool,
@@ -1572,18 +1569,16 @@ impl DomainMetadata {
15721569
self.domain.starts_with(INTERNAL_DOMAIN_PREFIX)
15731570
}
15741571

1575-
#[internal_api]
1576-
pub(crate) fn domain(&self) -> &str {
1572+
pub fn domain(&self) -> &str {
15771573
&self.domain
15781574
}
15791575

1580-
#[internal_api]
1581-
pub(crate) fn configuration(&self) -> &str {
1576+
pub fn configuration(&self) -> &str {
15821577
&self.configuration
15831578
}
15841579

15851580
/// Returns `true` if this action is a tombstone (marking domain removal).
1586-
pub(crate) fn is_removed(&self) -> bool {
1581+
pub fn is_removed(&self) -> bool {
15871582
self.removed
15881583
}
15891584
}

0 commit comments

Comments
 (0)