Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
a98c5f0
test(contract): refresh client_api_baseline before execution-guarante…
Yunnglin Sep 15, 2026
c359789
feat(infra): establish Sync_Dispatch_Path time bound (Phase 1, T1.1-T…
Yunnglin Sep 15, 2026
1b030ea
feat(contract): ErrorPayload contract + type base classes (Phase 2, T…
Yunnglin Sep 15, 2026
b6e0beb
feat(contract): QueueStateLiteral + naming disambiguation guard (Phas…
Yunnglin Sep 15, 2026
e46345b
feat(server): Blocking_Call_Boundary + Admission_Gate (Phase 3, T3.1-…
Yunnglin Sep 15, 2026
948daaa
feat(server): post-timeout actor recovery + two time bounds (Phase 4,…
Yunnglin Sep 15, 2026
742faf7
feat(state): future record survival + ownership hygiene (Phase 5, T5.…
Yunnglin Sep 15, 2026
f461fc3
refactor: remove all silent degradation mechanisms (Phase 7, T7.1-T7.9)
Yunnglin Sep 15, 2026
141b812
test(contract): zero-wire-change guard + CI/pre-commit closeout (Phas…
Yunnglin Sep 15, 2026
d54d9a1
fix(state): store state timestamps as UTC so expiry is timezone-indep…
Yunnglin Sep 15, 2026
250c380
Merge branch 'main' into feat/server-execution-guarantees
Yunnglin Sep 15, 2026
f978104
fix: restore multi lora state after load failure
Yunnglin Sep 15, 2026
26a4311
feat(server): finalize execution guarantees (backend boundary + strea…
Yunnglin Sep 15, 2026
d56bcca
fix: revert tinker to 0.16.1 and keep request types FastAPI-compatible
Yunnglin Sep 15, 2026
4bc9beb
fix(server): harden tinker GRPO execution guarantees
Yunnglin Sep 16, 2026
fc07df5
test(server): simplify execution guarantee coverage
Yunnglin Sep 16, 2026
9ea3272
feat(server): converge twinkle-native requests to submit/retrieve lif…
Yunnglin Sep 17, 2026
d848a5a
refactor(server): extract sampler seams and rename session-resource m…
Yunnglin Sep 17, 2026
b928a17
feat(server): request schema — strict wire models, preflight, and nam…
Yunnglin Sep 18, 2026
4f1addb
style(server): satisfy pre-commit lint on request-schema
Yunnglin Sep 18, 2026
637c53d
style(client): enforce lint on src/twinkle_client and normalize exist…
Yunnglin Sep 18, 2026
f7dc64e
refactor(client,server): module renames, agent-tools split, and rollo…
Yunnglin Sep 18, 2026
e037365
update client architecture
Yunnglin Sep 18, 2026
7ba6761
fix(model): PEFT 0.18.1 LoRA dtype autocast + static _ensure_lora_dty…
Yunnglin Sep 19, 2026
3b7461e
feat(server): harden request/error contracts (server-contract-hardeni…
Yunnglin Sep 20, 2026
7062b83
refactor(server): module boundaries — server/utils decomposition, Ser…
Yunnglin Sep 21, 2026
15acc7f
style: satisfy pre-commit lint (isort import order, pyupgrade unquote…
Yunnglin Sep 21, 2026
b00d385
style: pyupgrade unquotes forward-ref annotation in state/model_manag…
Yunnglin Sep 21, 2026
b20608f
test(server): streamline error payload coverage
Yunnglin Sep 21, 2026
d6d48fb
refactor: harden wire contract and client transport
Yunnglin Sep 21, 2026
4f13c1f
fix: preserve client entry compatibility and unify errors
Yunnglin Sep 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,11 @@ test_cookbook/
/test*.py
swanlog/
tests/server/config/_generated_e2e.yaml

# Full field-level contract surface: a generated artifact (8k+ lines, unreviewable diff).
# Regenerate via `python -m tests.server.contract.update_baseline`; do not commit it.
# NOTE: client_api_routes.json is the compact, COMMITTED guard -- do not ignore that one.
tests/server/contract/client_api_baseline.json

# Redis dump file produced by a local redis-server (test infra), never source.
*.rdb
22 changes: 11 additions & 11 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@ repos:
rev: 7.3.0
hooks:
- id: flake8
exclude: ^(examples/|cookbook/|client_tools/|src/twinkle_client/|tests/)
exclude: ^(examples/|cookbook/|client_tools/|tests/)

- repo: https://github.com/PyCQA/isort
rev: 7.0.0
hooks:
- id: isort
exclude: ^(examples/|cookbook/|client_tools/|src/twinkle_client/|tests/)
exclude: ^(examples/|cookbook/|client_tools/|tests/)

- repo: https://github.com/google/yapf
rev: v0.43.0
hooks:
- id: yapf
exclude: ^(examples/|cookbook/|client_tools/|src/twinkle_client/|tests/)
exclude: ^(examples/|cookbook/|client_tools/|tests/)

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
args: [--py38-plus]
exclude: ^(examples/|cookbook/|client_tools/|src/twinkle_client/|tests/)
exclude: ^(examples/|cookbook/|client_tools/|tests/)

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v6.0.0
hooks:
- id: trailing-whitespace
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: check-yaml
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: end-of-file-fixer
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: requirements-txt-fixer
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: double-quote-string-fixer
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: check-merge-conflict
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
- id: mixed-line-ending
args: ["--fix=lf"]
exclude: ^(client_tools/|src/twinkle_client/|tests/)
exclude: ^(client_tools/|tests/)
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ from twinkle import init_tinker_client
from twinkle.dataloader import DataLoader
from twinkle.dataset import Dataset, DatasetMeta
from twinkle.preprocessor import SelfCognitionProcessor
from twinkle.server.common import input_feature_to_datum
from twinkle.server.model.tinker_datum import input_feature_to_datum

base_model = 'ms://Qwen/Qwen3.8-27B'
base_url='your-base-url'
Expand Down
2 changes: 1 addition & 1 deletion README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ from twinkle import init_tinker_client
from twinkle.dataloader import DataLoader
from twinkle.dataset import Dataset, DatasetMeta
from twinkle.preprocessor import SelfCognitionProcessor
from twinkle.server.common import input_feature_to_datum
from twinkle.server.model.tinker_datum import input_feature_to_datum

base_model = 'ms://Qwen/Qwen3.8-27B'
base_url='your-base-url'
Expand Down
5 changes: 3 additions & 2 deletions cookbook/client/async_rl/client_orchestrated_grpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
from twinkle.dataset import Dataset, DatasetMeta
from twinkle.preprocessor.llm import GSM8KProcessor
from twinkle.reward import GSM8KAccuracyReward
from twinkle_client import DataPlaneClient, init_twinkle_client
from twinkle import init_twinkle_client
from twinkle_client import DataPlaneClient
from twinkle_client.async_rl import Worker, WorkerPipeline
from twinkle_client.common.json_utils import json_safe
from twinkle.protocol.json_utils import json_safe
from twinkle_client.model import MultiLoraTransformersModel
from twinkle_client.sampler import vLLMSampler

Expand Down
11 changes: 1 addition & 10 deletions cookbook/client/async_rl/server_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ telemetry:
otlp_endpoint: http://localhost:4317

persistence:
mode: file
file_path: /tmp/twinkle_state.json
mode: memory

applications:

Expand All @@ -42,9 +41,6 @@ applications:
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"

# TransferQueue-backed DataRef service.
- name: data-plane
Expand Down Expand Up @@ -95,7 +91,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "1"
TWINKLE_FAIL_FAST: "0"

# A second GPU hosts vLLM and loads the same local base model.
- name: sampler-Qwen3.5-4B
Expand Down Expand Up @@ -133,7 +128,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "1"
TWINKLE_FAIL_FAST: "0"

- name: processor
route_prefix: /api/v1/processor
Expand All @@ -155,6 +149,3 @@ applications:
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"
6 changes: 1 addition & 5 deletions cookbook/client/server/megatron/server_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ telemetry:
# Top-level placement makes the launcher propagate this to every Ray worker
# via env vars, so the configured backend is used regardless of which
# deployment initializes the ServerState actor first.
# mode: memory | file | redis
# mode: memory | redis
# memory: requires an initialized Ray runtime (the launcher handles this
# automatically; standalone scripts must call ray.init() first)
# file_path: required for `file` mode
# redis_url / key_prefix: required for `redis` mode
persistence:
mode: redis
Expand Down Expand Up @@ -54,7 +53,6 @@ applications:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "0"
TWINKLE_LONG_POLL_TIMEOUT: "120"
TWINKLE_FAIL_FAST: "0"

# 3. Sampler Service - Runs inference / sampling using vLLM engine
# Used for generating text from the model (e.g., evaluating LoRA results).
Expand Down Expand Up @@ -98,7 +96,6 @@ applications:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "0"
TWINKLE_LONG_POLL_TIMEOUT: "120"
TWINKLE_FAIL_FAST: "0"

# 2. Model Service - Hosts the base model for training.
# Config: PP=2 x DP=2 on 4 GPUs, ~27GB weights/GPU, comfortable for LoRA training
Expand Down Expand Up @@ -139,4 +136,3 @@ applications:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "0"
TWINKLE_LONG_POLL_TIMEOUT: "120"
TWINKLE_FAIL_FAST: "0"
8 changes: 0 additions & 8 deletions cookbook/client/server/megatron/server_config_4b.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,6 @@ applications:
target_ongoing_requests: 128 # Target concurrent requests per replica
ray_actor_options:
num_cpus: 0.1 # CPU resources allocated to this actor
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"

# 2. Model Service (commented out) - Would host the base model for training.
# Uncomment and configure if you need a training model worker.
Expand Down Expand Up @@ -71,7 +68,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "0"
TWINKLE_FAIL_FAST: "0"

# 3. Sampler Service - Runs inference / sampling using vLLM engine
# Used for generating text from the model (e.g., evaluating LoRA results).
Expand Down Expand Up @@ -109,7 +105,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "0"
TWINKLE_FAIL_FAST: "0"

# 4. Processor Service
- name: processor
Expand All @@ -132,6 +127,3 @@ applications:
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"
14 changes: 2 additions & 12 deletions cookbook/client/server/transformer/server_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,12 @@ telemetry:
# Top-level placement makes the launcher propagate this to every Ray worker
# via env vars, so the configured backend is used regardless of which
# deployment initializes the ServerState actor first.
# mode: memory | file | redis
# mode: memory | redis
# memory: requires an initialized Ray runtime (the launcher handles this
# automatically; standalone scripts must call ray.init() first)
# file_path: required for `file` mode
# redis_url / key_prefix: required for `redis` mode
persistence:
mode: file
file_path: /tmp/twinkle_state.json
mode: memory

# Applications: each entry defines a service component deployed on the server
applications:
Expand All @@ -49,9 +47,6 @@ applications:
target_ongoing_requests: 128 # Target concurrent requests per replica
ray_actor_options:
num_cpus: 0.1 # CPU resources allocated to this actor
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"

# 2. Model Service - Hosts the base model for training.
- name: models-Qwen3.5-4B
Expand Down Expand Up @@ -85,7 +80,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "1"
TWINKLE_FAIL_FAST: "0"

# 3. Sampler Service - Runs inference / sampling using vLLM engine
# Used for generating text from the model (e.g., evaluating LoRA results).
Expand Down Expand Up @@ -122,7 +116,6 @@ applications:
runtime_env:
env_vars:
TWINKLE_TRUST_REMOTE_CODE: "1"
TWINKLE_FAIL_FAST: "0"

# 4. Processor Service
- name: processor
Expand All @@ -145,6 +138,3 @@ applications:
target_ongoing_requests: 128
ray_actor_options:
num_cpus: 0.1
runtime_env:
env_vars:
TWINKLE_FAIL_FAST: "0"
5 changes: 3 additions & 2 deletions cookbook/client/tinker/dpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@
import swanlab

from tinker import types
from twinkle import init_tinker_client, get_logger
from twinkle import get_logger
from twinkle import init_tinker_client
from twinkle.dataset import Dataset, DatasetMeta, LazyDataset
from twinkle.dataloader import DataLoader
from twinkle.preprocessor import EmojiDPOProcessor
from twinkle.server.common import input_feature_to_datum
from twinkle.server.model.tinker_datum import input_feature_to_datum

logger = get_logger()

Expand Down
2 changes: 1 addition & 1 deletion cookbook/client/tinker/multi_modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from twinkle.preprocessor import Preprocessor
from twinkle.dataset import DatasetMeta, LazyDataset
from twinkle.dataloader import DataLoader
from twinkle.server.common import input_feature_to_datum # Key: converts InputFeature -> Datum
from twinkle.server.model.tinker_datum import input_feature_to_datum # Key: converts InputFeature -> Datum
from twinkle import get_logger

logger = get_logger()
Expand Down
2 changes: 1 addition & 1 deletion cookbook/client/tinker/self_cognition.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from twinkle.dataloader import DataLoader
from twinkle.dataset import Dataset, DatasetMeta
from twinkle.preprocessor import SelfCognitionProcessor
from twinkle.server.common import input_feature_to_datum
from twinkle.server.model.tinker_datum import input_feature_to_datum

# Initialize the Tinker client before importing ServiceClient
init_tinker_client()
Expand Down
11 changes: 7 additions & 4 deletions cookbook/client/tinker/upload_to_hub.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
#
# How it works:
# 1. The server submits the upload as a background task and returns a
# request_id immediately, so the HTTP call never times out.
# 2. The client polls /upload_status/{request_id} every few seconds and
# blocks until the upload completes or raises on failure.
# Task_Envelope with a request_id immediately, so the HTTP call never times out.
# 2. The client's future layer long-polls /twinkle/retrieve_future and blocks
# until the upload reaches a terminal state, raising on failure.
# (`upload_to_hub` keeps its `poll_interval` / `async_upload` arguments for
# signature compatibility; both are deprecated and have no effect.)
#
# Prerequisites:
# - Server must be running (see server.py / server_config.yaml)
Expand All @@ -20,7 +22,8 @@

import os

from twinkle import get_logger, init_twinkle_client
from twinkle import get_logger
from twinkle import init_twinkle_client
from twinkle_client.model import MultiLoraTransformersModel

logger = get_logger()
Expand Down
26 changes: 9 additions & 17 deletions cookbook/client/twinkle/dpo.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,19 @@

# Step 1: Load environment variables from a .env file (e.g., API tokens)
import dotenv
import os
from typing import Any, Dict, List

dotenv.load_dotenv('.env')
import numpy as np
import os
import torch
from peft import LoraConfig
from typing import Any, Dict, List

from twinkle import get_logger
from twinkle.dataset import Dataset, DatasetMeta
from twinkle_client import init_twinkle_client
from twinkle import init_twinkle_client
from twinkle.dataloader import DataLoader
from twinkle_client.model import MultiLoraTransformersModel
from twinkle.loss import DPOLoss
from twinkle.metric import DPOMetric
from twinkle.dataset import Dataset, DatasetMeta
from twinkle.preprocessor import EmojiDPOProcessor
from twinkle.processor import InputProcessor

dotenv.load_dotenv('.env')
logger = get_logger()

# Configuration (direct values, not from env)
Expand Down Expand Up @@ -68,11 +63,9 @@ def create_dpo_dataset():
dataset = Dataset(DatasetMeta(dataset_id, data_slice=range(100)))
dataset.set_template('Qwen3_5Template', model_id=f'ms://{base_model}', max_length=max_length)
dataset.map(
EmojiDPOProcessor,
init_args={
EmojiDPOProcessor, init_args={
'system': system_prompt,
}
)
})
# DPO preprocessor returns {'positive': [...], 'negative': [...]}
# batch_encode handles this format automatically
dataset.encode()
Expand Down Expand Up @@ -121,7 +114,7 @@ def train():
# Step 5: Configure the model

# Create a multi-LoRA Transformers model pointing to the base model on ModelScope
model = MultiLoraTransformersModel(model_id=f'ms://{base_model}')
model = client.model(f'ms://{base_model}')

# Define LoRA configuration: apply low-rank adapters to all linear layers
lora_config = LoraConfig(
Expand Down Expand Up @@ -162,7 +155,7 @@ def train():
optim_step = 0
max_steps = len(dataloader)
logger.info(f'Starting LoRA DPO training: loss_type={loss_type}, beta={dpo_beta}, lr={learning_rate}')
logger.info(f'Using base model (disable_lora=True) as reference model')
logger.info('Using base model (disable_lora=True) as reference model')

for batch in dataloader:
# batch is List[Dict] with 'positive' and 'negative' keys
Expand Down Expand Up @@ -199,7 +192,6 @@ def train():
# model.upload_to_hub(
# checkpoint_dir=twinkle_path,
# hub_model_id=hub_model_id,
# async_upload=False
# )
# logger.info(f"Uploaded checkpoint to hub: {hub_model_id}")

Expand Down
Loading
Loading