flare-kernel 0.1.0__tar.gz

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.
Files changed (27) hide show
  1. flare_kernel-0.1.0/PKG-INFO +67 -0
  2. flare_kernel-0.1.0/README.md +52 -0
  3. flare_kernel-0.1.0/pyproject.toml +28 -0
  4. flare_kernel-0.1.0/setup.cfg +4 -0
  5. flare_kernel-0.1.0/src/flare_kernel/__init__.py +9 -0
  6. flare_kernel-0.1.0/src/flare_kernel/app.py +27 -0
  7. flare_kernel-0.1.0/src/flare_kernel/contracts/__init__.py +5 -0
  8. flare_kernel-0.1.0/src/flare_kernel/contracts/kernel_contract.py +36 -0
  9. flare_kernel-0.1.0/src/flare_kernel/main.py +5 -0
  10. flare_kernel-0.1.0/src/flare_kernel/router/__init__.py +5 -0
  11. flare_kernel-0.1.0/src/flare_kernel/router/kernel.py +342 -0
  12. flare_kernel-0.1.0/src/flare_kernel/runtime/__init__.py +26 -0
  13. flare_kernel-0.1.0/src/flare_kernel/runtime/agent_runtime.py +113 -0
  14. flare_kernel-0.1.0/src/flare_kernel/runtime/domain_pack_loader.py +240 -0
  15. flare_kernel-0.1.0/src/flare_kernel/runtime/llm_provider.py +204 -0
  16. flare_kernel-0.1.0/src/flare_kernel/runtime/logging.py +21 -0
  17. flare_kernel-0.1.0/src/flare_kernel/runtime/mode_orchestration.py +330 -0
  18. flare_kernel-0.1.0/src/flare_kernel/runtime/mode_runtime.py +262 -0
  19. flare_kernel-0.1.0/src/flare_kernel/runtime/skill_runtime.py +105 -0
  20. flare_kernel-0.1.0/src/flare_kernel/runtime/tests/test_kernel_runtime.py +114 -0
  21. flare_kernel-0.1.0/src/flare_kernel/runtime/trace.py +11 -0
  22. flare_kernel-0.1.0/src/flare_kernel.egg-info/PKG-INFO +67 -0
  23. flare_kernel-0.1.0/src/flare_kernel.egg-info/SOURCES.txt +25 -0
  24. flare_kernel-0.1.0/src/flare_kernel.egg-info/dependency_links.txt +1 -0
  25. flare_kernel-0.1.0/src/flare_kernel.egg-info/requires.txt +4 -0
  26. flare_kernel-0.1.0/src/flare_kernel.egg-info/top_level.txt +1 -0
  27. flare_kernel-0.1.0/tests/test_basics.py +25 -0
@@ -0,0 +1,67 @@
1
+ Metadata-Version: 2.4
2
+ Name: flare-kernel
3
+ Version: 0.1.0
4
+ Summary: FLARE kernel runtime package
5
+ License: Proprietary
6
+ Classifier: Development Status :: 3 - Alpha
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: Programming Language :: Python :: 3.11
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: flare-engines<0.2.0,>=0.1.0
12
+ Requires-Dist: fastapi<1.0,>=0.115
13
+ Requires-Dist: pydantic<3,>=2
14
+ Requires-Dist: uvicorn<1.0,>=0.30
15
+
16
+ # flare-kernel
17
+
18
+ 通用编排与执行内核。
19
+
20
+ 职责:
21
+
22
+ 1. Decision 路由与策略入口。
23
+ 2. Execution 流程推进与状态管理。
24
+ 3. Runtime(含重试、超时、追踪)。
25
+ 4. 加载 domain pack 并执行。
26
+
27
+ ## Day 2 最小骨架
28
+
29
+ 目录:
30
+
31
+ 1. `src/flare_kernel/router`:接口路由
32
+ 2. `src/flare_kernel/runtime`:`trace_id` 与基础日志
33
+ 3. `src/flare_kernel/contracts`:请求/响应契约
34
+
35
+ 最小接口:
36
+
37
+ 1. `POST /kernel/run`
38
+ 2. `POST /kernel/stream`
39
+ 3. `GET /kernel/health`
40
+
41
+ kernel 现已输出 mode/context 运行时占位事件与字段。
42
+
43
+ ## Instance 注入(品牌信息)
44
+
45
+ 1. kernel 支持从 instance 的 domain-pack 读取品牌配置:
46
+ `branding/instance-branding.json`
47
+ 2. 读取优先级:
48
+ - 环境变量 `FLARE_DOMAIN_PACK_ROOT`
49
+ - 自动探测 `apps/<instance_id>/domain-pack`
50
+ 3. 注入位置:
51
+ - `POST /kernel/run` 响应 `result.instance_profile`
52
+ - `POST /kernel/stream` SSE 事件 `instance_profile`
53
+
54
+ 说明:品牌注入仅在 instance 层配置,core 不写死产品名、logo、标签。
55
+
56
+ 本地启动(示例):
57
+
58
+ ```bash
59
+ uvicorn flare_kernel.main:app --app-dir packages/flare-kernel/src --host 0.0.0.0 --port 8002
60
+ ```
61
+
62
+ ## 最小发布说明
63
+
64
+ 1. 当前包版本:`0.1.0`
65
+ 2. 发布元数据:`packages/flare-kernel/pyproject.toml`
66
+ 3. 本地构建:`python -m build`
67
+ 4. 本地安装:`pip install packages/flare-kernel`
@@ -0,0 +1,52 @@
1
+ # flare-kernel
2
+
3
+ 通用编排与执行内核。
4
+
5
+ 职责:
6
+
7
+ 1. Decision 路由与策略入口。
8
+ 2. Execution 流程推进与状态管理。
9
+ 3. Runtime(含重试、超时、追踪)。
10
+ 4. 加载 domain pack 并执行。
11
+
12
+ ## Day 2 最小骨架
13
+
14
+ 目录:
15
+
16
+ 1. `src/flare_kernel/router`:接口路由
17
+ 2. `src/flare_kernel/runtime`:`trace_id` 与基础日志
18
+ 3. `src/flare_kernel/contracts`:请求/响应契约
19
+
20
+ 最小接口:
21
+
22
+ 1. `POST /kernel/run`
23
+ 2. `POST /kernel/stream`
24
+ 3. `GET /kernel/health`
25
+
26
+ kernel 现已输出 mode/context 运行时占位事件与字段。
27
+
28
+ ## Instance 注入(品牌信息)
29
+
30
+ 1. kernel 支持从 instance 的 domain-pack 读取品牌配置:
31
+ `branding/instance-branding.json`
32
+ 2. 读取优先级:
33
+ - 环境变量 `FLARE_DOMAIN_PACK_ROOT`
34
+ - 自动探测 `apps/<instance_id>/domain-pack`
35
+ 3. 注入位置:
36
+ - `POST /kernel/run` 响应 `result.instance_profile`
37
+ - `POST /kernel/stream` SSE 事件 `instance_profile`
38
+
39
+ 说明:品牌注入仅在 instance 层配置,core 不写死产品名、logo、标签。
40
+
41
+ 本地启动(示例):
42
+
43
+ ```bash
44
+ uvicorn flare_kernel.main:app --app-dir packages/flare-kernel/src --host 0.0.0.0 --port 8002
45
+ ```
46
+
47
+ ## 最小发布说明
48
+
49
+ 1. 当前包版本:`0.1.0`
50
+ 2. 发布元数据:`packages/flare-kernel/pyproject.toml`
51
+ 3. 本地构建:`python -m build`
52
+ 4. 本地安装:`pip install packages/flare-kernel`
@@ -0,0 +1,28 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "flare-kernel"
7
+ version = "0.1.0"
8
+ description = "FLARE kernel runtime package"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ dependencies = [
12
+ "flare-engines>=0.1.0,<0.2.0",
13
+ "fastapi>=0.115,<1.0",
14
+ "pydantic>=2,<3",
15
+ "uvicorn>=0.30,<1.0",
16
+ ]
17
+ license = { text = "Proprietary" }
18
+ classifiers = [
19
+ "Development Status :: 3 - Alpha",
20
+ "Programming Language :: Python :: 3",
21
+ "Programming Language :: Python :: 3.11",
22
+ ]
23
+
24
+ [tool.setuptools]
25
+ package-dir = {"" = "src"}
26
+
27
+ [tool.setuptools.packages.find]
28
+ where = ["src"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ """flare-kernel package."""
2
+
3
+ __all__ = ["create_app"]
4
+
5
+
6
+ def create_app():
7
+ from flare_kernel.app import create_app as _create_app
8
+
9
+ return _create_app()
@@ -0,0 +1,27 @@
1
+ """FastAPI app factory for flare-kernel."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from fastapi import FastAPI
6
+ from fastapi.middleware.cors import CORSMiddleware
7
+
8
+ from flare_kernel.router import kernel_router
9
+
10
+
11
+ def create_app() -> FastAPI:
12
+ app = FastAPI(
13
+ title="FLARE Kernel",
14
+ version="0.1.0",
15
+ description="FLARE kernel minimal runtime",
16
+ )
17
+
18
+ app.add_middleware(
19
+ CORSMiddleware,
20
+ allow_origins=["*"],
21
+ allow_credentials=True,
22
+ allow_methods=["*"],
23
+ allow_headers=["*"],
24
+ )
25
+
26
+ app.include_router(kernel_router)
27
+ return app
@@ -0,0 +1,5 @@
1
+ """Kernel contracts."""
2
+
3
+ from flare_kernel.contracts.kernel_contract import HealthResponse, KernelRequest, KernelResponse
4
+
5
+ __all__ = ["KernelRequest", "KernelResponse", "HealthResponse"]
@@ -0,0 +1,36 @@
1
+ """Kernel API contracts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Literal
6
+
7
+ from pydantic import BaseModel, Field
8
+
9
+
10
+ class KernelRequest(BaseModel):
11
+ tenant_id: str = "default"
12
+ instance_id: str = "xiaocai-instance"
13
+ domain_pack_version: str = "v1"
14
+ session_id: str = "default"
15
+ intent: str = "default"
16
+ payload: dict[str, Any] = Field(default_factory=dict)
17
+ context_refs: list[Any] = Field(default_factory=list)
18
+ action_key: str | None = None
19
+ target_mode: str | None = None
20
+ action_status: str | None = None
21
+ action_reason: str | None = None
22
+ trace_id: str | None = None
23
+
24
+
25
+ class KernelResponse(BaseModel):
26
+ trace_id: str
27
+ state: Literal["RUNNING", "SUCCEEDED", "FAILED"]
28
+ events: list[dict[str, Any]] = Field(default_factory=list)
29
+ result: dict[str, Any] = Field(default_factory=dict)
30
+ next_actions: list[dict[str, Any]] = Field(default_factory=list)
31
+
32
+
33
+ class HealthResponse(BaseModel):
34
+ status: Literal["healthy"]
35
+ service: str
36
+ trace_id: str
@@ -0,0 +1,5 @@
1
+ """ASGI entrypoint."""
2
+
3
+ from flare_kernel.app import create_app
4
+
5
+ app = create_app()
@@ -0,0 +1,5 @@
1
+ """Kernel routers."""
2
+
3
+ from flare_kernel.router.kernel import router as kernel_router
4
+
5
+ __all__ = ["kernel_router"]
@@ -0,0 +1,342 @@
1
+ """Kernel API router."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import json
6
+ from typing import Any
7
+
8
+ from fastapi import APIRouter
9
+ from fastapi.responses import StreamingResponse
10
+
11
+ from flare_kernel.contracts import HealthResponse, KernelRequest, KernelResponse
12
+ from flare_kernel.runtime import build_kernel_runtime, generate_llm_completion, get_logger, load_instance_profile, resolve_trace_id
13
+
14
+ router = APIRouter(prefix="/kernel", tags=["kernel"])
15
+ logger = get_logger("flare_kernel.router.kernel")
16
+
17
+
18
+ def _build_prompt(
19
+ req: KernelRequest,
20
+ instance_profile: dict[str, object] | None,
21
+ *,
22
+ intent: str | None = None,
23
+ ) -> str:
24
+ message = ""
25
+ if isinstance(req.payload, dict):
26
+ raw_message = req.payload.get("message")
27
+ if isinstance(raw_message, str):
28
+ message = raw_message.strip()
29
+
30
+ product_name = ""
31
+ if instance_profile and isinstance(instance_profile.get("product_name"), str):
32
+ product_name = instance_profile.get("product_name", "").strip()
33
+
34
+ prompt_parts = [
35
+ f"intent: {intent or req.intent}",
36
+ f"session_id: {req.session_id}",
37
+ ]
38
+ if product_name:
39
+ prompt_parts.append(f"product_name: {product_name}")
40
+ if message:
41
+ prompt_parts.append(f"user_message: {message}")
42
+ return "\n".join(prompt_parts)
43
+
44
+
45
+ def _normalize_key(value: Any) -> str:
46
+ if value is None:
47
+ return ""
48
+ return str(value).strip().lower().replace("-", "_").replace(" ", "_")
49
+
50
+
51
+ def _extract_value(raw_value: Any) -> Any:
52
+ if isinstance(raw_value, dict):
53
+ for candidate in ("value", "content", "text"):
54
+ candidate_value = raw_value.get(candidate)
55
+ if candidate_value not in (None, "", [], {}):
56
+ return candidate_value
57
+ return raw_value
58
+
59
+
60
+ def _collect_sourcing_base_fields(payload: dict[str, Any]) -> dict[str, Any]:
61
+ raw_base_fields = payload.get("base_fields")
62
+ if isinstance(raw_base_fields, dict):
63
+ return dict(raw_base_fields)
64
+
65
+ base_fields: dict[str, Any] = {}
66
+ raw_fields = payload.get("fields")
67
+
68
+ if isinstance(raw_fields, dict):
69
+ for key in ("category", "region"):
70
+ if key not in raw_fields:
71
+ continue
72
+ value = _extract_value(raw_fields.get(key))
73
+ if value not in (None, "", [], {}):
74
+ base_fields[key] = value
75
+ elif isinstance(raw_fields, list):
76
+ for raw_item in raw_fields:
77
+ if not isinstance(raw_item, dict):
78
+ continue
79
+ field_key = ""
80
+ for candidate in ("field_key", "name", "id", "key", "label"):
81
+ candidate_value = raw_item.get(candidate)
82
+ if isinstance(candidate_value, str) and candidate_value.strip():
83
+ field_key = candidate_value.strip()
84
+ break
85
+ normalized_key = _normalize_key(field_key)
86
+ if normalized_key not in {"category", "region"}:
87
+ continue
88
+ value = _extract_value(raw_item.get("value", raw_item.get("content", raw_item.get("text"))))
89
+ if value not in (None, "", [], {}):
90
+ base_fields[normalized_key] = value
91
+
92
+ for key in ("category", "region"):
93
+ if key in base_fields:
94
+ continue
95
+ value = payload.get(key)
96
+ if value not in (None, "", [], {}):
97
+ base_fields[key] = value
98
+
99
+ return base_fields
100
+
101
+
102
+ def _resolve_action_target_mode(req: KernelRequest) -> str:
103
+ target_mode = req.target_mode
104
+ if isinstance(target_mode, str):
105
+ normalized = target_mode.strip()
106
+ if normalized in {"requirement_canvas", "intelligent_sourcing"}:
107
+ return normalized
108
+
109
+ action_key = req.action_key if isinstance(req.action_key, str) else ""
110
+ if action_key == "handoff_to_sourcing":
111
+ return "intelligent_sourcing"
112
+ if action_key == "continue_collection":
113
+ return "requirement_canvas"
114
+
115
+ return req.intent if isinstance(req.intent, str) and req.intent.strip() else "default"
116
+
117
+
118
+ def _build_action_payload(req: KernelRequest, target_mode: str) -> dict[str, Any]:
119
+ payload = dict(req.payload) if isinstance(req.payload, dict) else {}
120
+ payload["function_type"] = target_mode
121
+ payload["target_mode"] = target_mode
122
+ if isinstance(req.action_key, str) and req.action_key.strip():
123
+ payload["action_key"] = req.action_key.strip()
124
+ if isinstance(req.action_status, str) and req.action_status.strip():
125
+ payload["action_status"] = req.action_status.strip()
126
+ if isinstance(req.action_reason, str) and req.action_reason.strip():
127
+ payload["action_reason"] = req.action_reason.strip()
128
+
129
+ if target_mode == "intelligent_sourcing":
130
+ base_fields = _collect_sourcing_base_fields(payload)
131
+ if base_fields:
132
+ payload["base_fields"] = base_fields
133
+
134
+ return payload
135
+
136
+
137
+ @router.get("/health", response_model=HealthResponse)
138
+ async def kernel_health() -> HealthResponse:
139
+ trace_id = resolve_trace_id(None)
140
+ logger.info("kernel.health trace_id=%s", trace_id)
141
+ return HealthResponse(status="healthy", service="flare-kernel", trace_id=trace_id)
142
+
143
+
144
+ @router.post("/run", response_model=KernelResponse)
145
+ async def kernel_run(req: KernelRequest) -> KernelResponse:
146
+ trace_id = resolve_trace_id(req.trace_id)
147
+ instance_profile = load_instance_profile(req.instance_id)
148
+ runtime_snapshot = build_kernel_runtime(
149
+ trace_id=trace_id,
150
+ tenant_id=req.tenant_id,
151
+ instance_id=req.instance_id,
152
+ domain_pack_version=req.domain_pack_version,
153
+ session_id=req.session_id,
154
+ intent=req.intent,
155
+ payload=req.payload,
156
+ instance_profile=instance_profile,
157
+ )
158
+ logger.info(
159
+ "kernel.run trace_id=%s session_id=%s intent=%s instance_id=%s has_instance_profile=%s",
160
+ trace_id,
161
+ req.session_id,
162
+ req.intent,
163
+ req.instance_id,
164
+ bool(instance_profile),
165
+ )
166
+ completion = await generate_llm_completion(
167
+ _build_prompt(req, instance_profile),
168
+ trace_id=trace_id,
169
+ session_id=req.session_id,
170
+ intent=req.intent,
171
+ )
172
+ result = {
173
+ "message": completion.content,
174
+ "provider": completion.provider,
175
+ "model": completion.model,
176
+ "provider_status": completion.status,
177
+ "mode_key": runtime_snapshot["mode_key"],
178
+ "mode_state": runtime_snapshot["mode_state"],
179
+ "mode_runtime": runtime_snapshot["mode_runtime"],
180
+ "context_usage": runtime_snapshot["context_usage"],
181
+ "agent_runtime": runtime_snapshot["agent_runtime"],
182
+ "skill_runtime": runtime_snapshot["skill_runtime"],
183
+ "mode_events": runtime_snapshot["mode_events"],
184
+ "next_actions": runtime_snapshot["next_actions"],
185
+ }
186
+ if instance_profile:
187
+ result["instance_profile"] = instance_profile
188
+ return KernelResponse(
189
+ trace_id=trace_id,
190
+ state="SUCCEEDED",
191
+ events=[],
192
+ result=result,
193
+ next_actions=runtime_snapshot["next_actions"],
194
+ )
195
+
196
+
197
+ @router.post("/action", response_model=KernelResponse)
198
+ async def kernel_action(req: KernelRequest) -> KernelResponse:
199
+ trace_id = resolve_trace_id(req.trace_id)
200
+ instance_profile = load_instance_profile(req.instance_id)
201
+ action_target_mode = _resolve_action_target_mode(req)
202
+ action_payload = _build_action_payload(req, action_target_mode)
203
+ runtime_snapshot = build_kernel_runtime(
204
+ trace_id=trace_id,
205
+ tenant_id=req.tenant_id,
206
+ instance_id=req.instance_id,
207
+ domain_pack_version=req.domain_pack_version,
208
+ session_id=req.session_id,
209
+ intent=action_target_mode,
210
+ payload=action_payload,
211
+ instance_profile=instance_profile,
212
+ )
213
+ logger.info(
214
+ "kernel.action trace_id=%s session_id=%s intent=%s action_key=%s target_mode=%s instance_id=%s has_instance_profile=%s",
215
+ trace_id,
216
+ req.session_id,
217
+ req.intent,
218
+ req.action_key,
219
+ action_target_mode,
220
+ req.instance_id,
221
+ bool(instance_profile),
222
+ )
223
+ completion = await generate_llm_completion(
224
+ _build_prompt(req, instance_profile, intent=action_target_mode),
225
+ trace_id=trace_id,
226
+ session_id=req.session_id,
227
+ intent=action_target_mode,
228
+ )
229
+ result = {
230
+ "message": completion.content,
231
+ "provider": completion.provider,
232
+ "model": completion.model,
233
+ "provider_status": completion.status,
234
+ "mode_key": runtime_snapshot["mode_key"],
235
+ "mode_state": runtime_snapshot["mode_state"],
236
+ "mode_runtime": runtime_snapshot["mode_runtime"],
237
+ "context_usage": runtime_snapshot["context_usage"],
238
+ "agent_runtime": runtime_snapshot["agent_runtime"],
239
+ "skill_runtime": runtime_snapshot["skill_runtime"],
240
+ "mode_events": runtime_snapshot["mode_events"],
241
+ "next_actions": runtime_snapshot["next_actions"],
242
+ "selected_action": {
243
+ "action_key": req.action_key,
244
+ "target_mode": action_target_mode,
245
+ "status": req.action_status,
246
+ "reason": req.action_reason,
247
+ },
248
+ }
249
+ if instance_profile:
250
+ result["instance_profile"] = instance_profile
251
+ return KernelResponse(
252
+ trace_id=trace_id,
253
+ state="SUCCEEDED",
254
+ events=[],
255
+ result=result,
256
+ next_actions=runtime_snapshot["next_actions"],
257
+ )
258
+
259
+
260
+ @router.post("/stream")
261
+ async def kernel_stream(req: KernelRequest) -> StreamingResponse:
262
+ trace_id = resolve_trace_id(req.trace_id)
263
+ instance_profile = load_instance_profile(req.instance_id)
264
+ runtime_snapshot = build_kernel_runtime(
265
+ trace_id=trace_id,
266
+ tenant_id=req.tenant_id,
267
+ instance_id=req.instance_id,
268
+ domain_pack_version=req.domain_pack_version,
269
+ session_id=req.session_id,
270
+ intent=req.intent,
271
+ payload=req.payload,
272
+ instance_profile=instance_profile,
273
+ )
274
+ logger.info(
275
+ "kernel.stream trace_id=%s session_id=%s intent=%s instance_id=%s has_instance_profile=%s",
276
+ trace_id,
277
+ req.session_id,
278
+ req.intent,
279
+ req.instance_id,
280
+ bool(instance_profile),
281
+ )
282
+
283
+ async def event_stream():
284
+ running = {"trace_id": trace_id, "state": "RUNNING", "events": [], "result": {}, "next_actions": []}
285
+ yield f"event: status\ndata: {json.dumps(running, ensure_ascii=False)}\n\n"
286
+
287
+ if instance_profile:
288
+ profile_event = {"trace_id": trace_id, "instance_profile": instance_profile}
289
+ yield f"event: instance_profile\ndata: {json.dumps(profile_event, ensure_ascii=False)}\n\n"
290
+
291
+ mode_runtime_event = {"trace_id": trace_id, **runtime_snapshot["mode_runtime"]}
292
+ yield f"event: mode_runtime\ndata: {json.dumps(mode_runtime_event, ensure_ascii=False)}\n\n"
293
+
294
+ context_usage_event = {"trace_id": trace_id, **runtime_snapshot["context_usage"]}
295
+ yield f"event: context_usage\ndata: {json.dumps(context_usage_event, ensure_ascii=False)}\n\n"
296
+
297
+ agent_runtime_event = {"trace_id": trace_id, **runtime_snapshot["agent_runtime"]}
298
+ yield f"event: agent_runtime\ndata: {json.dumps(agent_runtime_event, ensure_ascii=False)}\n\n"
299
+
300
+ skill_runtime_event = {"trace_id": trace_id, **runtime_snapshot["skill_runtime"]}
301
+ yield f"event: skill_runtime\ndata: {json.dumps(skill_runtime_event, ensure_ascii=False)}\n\n"
302
+
303
+ for mode_event in runtime_snapshot["mode_events"]:
304
+ event_type = mode_event.get("event_type")
305
+ if not isinstance(event_type, str) or not event_type.strip():
306
+ continue
307
+ event_payload = mode_event.get("payload")
308
+ if isinstance(event_payload, dict):
309
+ event_data = {"trace_id": trace_id, **event_payload}
310
+ else:
311
+ event_data = {"trace_id": trace_id, "payload": event_payload}
312
+ yield f"event: {event_type}\ndata: {json.dumps(event_data, ensure_ascii=False)}\n\n"
313
+
314
+ product_name = ""
315
+ if instance_profile and isinstance(instance_profile.get("product_name"), str):
316
+ product_name = instance_profile.get("product_name", "").strip()
317
+ completion = await generate_llm_completion(
318
+ _build_prompt(req, instance_profile),
319
+ trace_id=trace_id,
320
+ session_id=req.session_id,
321
+ intent=req.intent,
322
+ )
323
+ content_text = completion.content
324
+ if product_name and completion.status == "placeholder" and "kernel.stream placeholder" not in content_text:
325
+ content_text = f"{product_name} {content_text}".strip()
326
+ content = {
327
+ "trace_id": trace_id,
328
+ "content": content_text,
329
+ "provider": completion.provider,
330
+ "model": completion.model,
331
+ "provider_status": completion.status,
332
+ }
333
+ yield f"event: content\ndata: {json.dumps(content, ensure_ascii=False)}\n\n"
334
+
335
+ complete = {"trace_id": trace_id, "status": "done"}
336
+ yield f"event: complete\ndata: {json.dumps(complete, ensure_ascii=False)}\n\n"
337
+
338
+ return StreamingResponse(
339
+ event_stream(),
340
+ media_type="text/event-stream",
341
+ headers={"Cache-Control": "no-cache", "Connection": "keep-alive"},
342
+ )
@@ -0,0 +1,26 @@
1
+ """Kernel runtime helpers."""
2
+
3
+ from flare_kernel.runtime.domain_pack_loader import load_instance_profile, resolve_domain_pack_root
4
+ from flare_kernel.runtime.logging import get_logger
5
+ from flare_kernel.runtime.llm_provider import generate_llm_completion, get_llm_provider_config
6
+ from flare_kernel.runtime.mode_runtime import build_kernel_runtime, build_mode_runtime, build_context_usage, get_context_budget_config
7
+ from flare_kernel.runtime.mode_orchestration import build_mode_orchestration
8
+ from flare_kernel.runtime.agent_runtime import build_agent_runtime
9
+ from flare_kernel.runtime.skill_runtime import build_skill_runtime
10
+ from flare_kernel.runtime.trace import resolve_trace_id
11
+
12
+ __all__ = [
13
+ "resolve_trace_id",
14
+ "get_logger",
15
+ "resolve_domain_pack_root",
16
+ "load_instance_profile",
17
+ "get_llm_provider_config",
18
+ "generate_llm_completion",
19
+ "get_context_budget_config",
20
+ "build_mode_runtime",
21
+ "build_context_usage",
22
+ "build_mode_orchestration",
23
+ "build_agent_runtime",
24
+ "build_skill_runtime",
25
+ "build_kernel_runtime",
26
+ ]