world-model-optimizer 0.2.0__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.
Files changed (308) hide show
  1. llm_waterfall/LICENSE +21 -0
  2. llm_waterfall/__init__.py +53 -0
  3. llm_waterfall/adapters/__init__.py +36 -0
  4. llm_waterfall/adapters/anthropic.py +105 -0
  5. llm_waterfall/adapters/aws_mantle.py +47 -0
  6. llm_waterfall/adapters/azure_openai.py +71 -0
  7. llm_waterfall/adapters/base.py +51 -0
  8. llm_waterfall/adapters/bedrock.py +309 -0
  9. llm_waterfall/adapters/openai.py +130 -0
  10. llm_waterfall/classify.py +184 -0
  11. llm_waterfall/pricing.py +110 -0
  12. llm_waterfall/py.typed +0 -0
  13. llm_waterfall/types.py +295 -0
  14. llm_waterfall/waterfall.py +255 -0
  15. wmo/__init__.py +38 -0
  16. wmo/agents/__init__.py +7 -0
  17. wmo/agents/default.py +29 -0
  18. wmo/agents/meta.py +55 -0
  19. wmo/agents/optimizer.py +55 -0
  20. wmo/agents/project.py +928 -0
  21. wmo/cli/__init__.py +5 -0
  22. wmo/cli/agent_session.py +1123 -0
  23. wmo/cli/app.py +2489 -0
  24. wmo/cli/e2b_cmds.py +212 -0
  25. wmo/cli/eval_closed_loop.py +207 -0
  26. wmo/cli/harness_app.py +1147 -0
  27. wmo/cli/harness_distill.py +659 -0
  28. wmo/cli/hosted_session.py +880 -0
  29. wmo/cli/ingest_cmd.py +165 -0
  30. wmo/cli/model_roles.py +82 -0
  31. wmo/cli/platform_cmds.py +372 -0
  32. wmo/cli/route_app.py +274 -0
  33. wmo/cli/session_state.py +243 -0
  34. wmo/cli/ui.py +1107 -0
  35. wmo/cli/workspace_sync.py +504 -0
  36. wmo/config/__init__.py +60 -0
  37. wmo/config/card.py +129 -0
  38. wmo/config/config.py +367 -0
  39. wmo/config/dotenv.py +67 -0
  40. wmo/config/settings.py +128 -0
  41. wmo/config/store.py +177 -0
  42. wmo/conftest.py +19 -0
  43. wmo/connect/__init__.py +88 -0
  44. wmo/connect/apps.py +78 -0
  45. wmo/connect/brave.py +284 -0
  46. wmo/connect/connector.py +79 -0
  47. wmo/connect/credentials.py +164 -0
  48. wmo/connect/github.py +321 -0
  49. wmo/connect/google.py +627 -0
  50. wmo/connect/notion.py +790 -0
  51. wmo/connect/oauth.py +461 -0
  52. wmo/connect/slack.py +555 -0
  53. wmo/connect/store.py +199 -0
  54. wmo/connect/types.py +156 -0
  55. wmo/core/__init__.py +21 -0
  56. wmo/core/parsing.py +281 -0
  57. wmo/core/render.py +271 -0
  58. wmo/core/text.py +40 -0
  59. wmo/core/types.py +116 -0
  60. wmo/distill/__init__.py +14 -0
  61. wmo/distill/agents.py +140 -0
  62. wmo/distill/config.py +1006 -0
  63. wmo/distill/cost.py +437 -0
  64. wmo/distill/data.py +921 -0
  65. wmo/distill/deadlines.py +254 -0
  66. wmo/distill/fake_tinker.py +734 -0
  67. wmo/distill/gate.py +122 -0
  68. wmo/distill/loop.py +3499 -0
  69. wmo/distill/renderers.py +399 -0
  70. wmo/distill/rendering.py +620 -0
  71. wmo/distill/rollouts.py +726 -0
  72. wmo/distill/samples.py +195 -0
  73. wmo/distill/store.py +829 -0
  74. wmo/distill/teacher.py +714 -0
  75. wmo/distill/tokens.py +535 -0
  76. wmo/distill/tracking.py +552 -0
  77. wmo/distill/tripwire.py +411 -0
  78. wmo/distill/xtoken/byte_offsets.py +152 -0
  79. wmo/distill/xtoken/chunks.py +457 -0
  80. wmo/distill/xtoken/prompt_logprobs.py +475 -0
  81. wmo/distill/xtoken/teacher_render.py +346 -0
  82. wmo/engine/__init__.py +28 -0
  83. wmo/engine/autoconfig.py +367 -0
  84. wmo/engine/build.py +346 -0
  85. wmo/engine/demo.py +77 -0
  86. wmo/engine/eval_suites.py +245 -0
  87. wmo/engine/grounding.py +491 -0
  88. wmo/engine/knowledge.py +291 -0
  89. wmo/engine/loader.py +36 -0
  90. wmo/engine/play.py +92 -0
  91. wmo/engine/prompts.py +99 -0
  92. wmo/engine/replay.py +443 -0
  93. wmo/engine/reporting.py +58 -0
  94. wmo/engine/workspace.py +468 -0
  95. wmo/engine/world_model.py +568 -0
  96. wmo/env/__init__.py +22 -0
  97. wmo/env/base.py +121 -0
  98. wmo/env/closed_loop.py +229 -0
  99. wmo/env/episode.py +107 -0
  100. wmo/env/llm_agent.py +93 -0
  101. wmo/env/scenarios.py +73 -0
  102. wmo/evals/__init__.py +52 -0
  103. wmo/evals/agreement.py +110 -0
  104. wmo/evals/base.py +45 -0
  105. wmo/evals/closed_loop.py +480 -0
  106. wmo/evals/failover.py +96 -0
  107. wmo/evals/gold.py +127 -0
  108. wmo/evals/grid.py +394 -0
  109. wmo/evals/grid_plot.py +205 -0
  110. wmo/evals/harbor/__init__.py +27 -0
  111. wmo/evals/harbor/agent.py +573 -0
  112. wmo/evals/harbor/ctrf.py +171 -0
  113. wmo/evals/harbor/e2b_environment.py +587 -0
  114. wmo/evals/harbor/e2b_template_policy.py +144 -0
  115. wmo/evals/harbor/scorer.py +875 -0
  116. wmo/evals/harbor/tasks.py +140 -0
  117. wmo/evals/open_loop.py +194 -0
  118. wmo/evals/tasks.py +53 -0
  119. wmo/harness/__init__.py +51 -0
  120. wmo/harness/code_runtime.py +288 -0
  121. wmo/harness/create.py +1191 -0
  122. wmo/harness/delta.py +220 -0
  123. wmo/harness/doc.py +556 -0
  124. wmo/harness/e2b_ledger.py +342 -0
  125. wmo/harness/e2b_reap.py +476 -0
  126. wmo/harness/e2b_sandbox.py +350 -0
  127. wmo/harness/environment.py +35 -0
  128. wmo/harness/live_session.py +543 -0
  129. wmo/harness/mutate.py +343 -0
  130. wmo/harness/pi_e2b.py +1710 -0
  131. wmo/harness/pi_entry/entry.ts +268 -0
  132. wmo/harness/pi_entry/runner_frames.ts +92 -0
  133. wmo/harness/pi_entry/runner_live.ts +587 -0
  134. wmo/harness/pi_entry/runner_service.ts +270 -0
  135. wmo/harness/pi_entry/runner_stdio.ts +374 -0
  136. wmo/harness/pi_entry/runner_termination.ts +142 -0
  137. wmo/harness/pi_local.py +262 -0
  138. wmo/harness/pi_runtime.py +495 -0
  139. wmo/harness/pi_vendor.py +65 -0
  140. wmo/harness/population.py +509 -0
  141. wmo/harness/project_proposer.py +569 -0
  142. wmo/harness/proposer.py +977 -0
  143. wmo/harness/runner_link.py +619 -0
  144. wmo/harness/runtime.py +389 -0
  145. wmo/harness/scoring.py +247 -0
  146. wmo/harness/skills.py +116 -0
  147. wmo/harness/source_tree.py +319 -0
  148. wmo/harness/store.py +176 -0
  149. wmo/harness/tools.py +105 -0
  150. wmo/harness/vendor/manifest.sha256 +58 -0
  151. wmo/harness/vendor/pi-agent/CHANGELOG.md +556 -0
  152. wmo/harness/vendor/pi-agent/LICENSE +21 -0
  153. wmo/harness/vendor/pi-agent/README.md +488 -0
  154. wmo/harness/vendor/pi-agent/VENDOR.md +39 -0
  155. wmo/harness/vendor/pi-agent/docs/agent-harness.md +486 -0
  156. wmo/harness/vendor/pi-agent/docs/durable-harness.md +212 -0
  157. wmo/harness/vendor/pi-agent/docs/hooks.md +445 -0
  158. wmo/harness/vendor/pi-agent/docs/models.md +966 -0
  159. wmo/harness/vendor/pi-agent/docs/observability.md +376 -0
  160. wmo/harness/vendor/pi-agent/package.json +60 -0
  161. wmo/harness/vendor/pi-agent/src/agent-loop.ts +748 -0
  162. wmo/harness/vendor/pi-agent/src/agent.ts +575 -0
  163. wmo/harness/vendor/pi-agent/src/harness/agent-harness.ts +1029 -0
  164. wmo/harness/vendor/pi-agent/src/harness/compaction/branch-summarization.ts +261 -0
  165. wmo/harness/vendor/pi-agent/src/harness/compaction/compaction.ts +747 -0
  166. wmo/harness/vendor/pi-agent/src/harness/compaction/utils.ts +144 -0
  167. wmo/harness/vendor/pi-agent/src/harness/env/nodejs.ts +550 -0
  168. wmo/harness/vendor/pi-agent/src/harness/messages.ts +164 -0
  169. wmo/harness/vendor/pi-agent/src/harness/prompt-templates.ts +267 -0
  170. wmo/harness/vendor/pi-agent/src/harness/session/jsonl-repo.ts +177 -0
  171. wmo/harness/vendor/pi-agent/src/harness/session/jsonl-storage.ts +293 -0
  172. wmo/harness/vendor/pi-agent/src/harness/session/memory-repo.ts +50 -0
  173. wmo/harness/vendor/pi-agent/src/harness/session/memory-storage.ts +131 -0
  174. wmo/harness/vendor/pi-agent/src/harness/session/repo-utils.ts +51 -0
  175. wmo/harness/vendor/pi-agent/src/harness/session/session.ts +267 -0
  176. wmo/harness/vendor/pi-agent/src/harness/session/uuid.ts +54 -0
  177. wmo/harness/vendor/pi-agent/src/harness/skills.ts +375 -0
  178. wmo/harness/vendor/pi-agent/src/harness/system-prompt.ts +34 -0
  179. wmo/harness/vendor/pi-agent/src/harness/types.ts +836 -0
  180. wmo/harness/vendor/pi-agent/src/harness/utils/shell-output.ts +135 -0
  181. wmo/harness/vendor/pi-agent/src/harness/utils/truncate.ts +344 -0
  182. wmo/harness/vendor/pi-agent/src/index.ts +44 -0
  183. wmo/harness/vendor/pi-agent/src/node.ts +2 -0
  184. wmo/harness/vendor/pi-agent/src/proxy.ts +367 -0
  185. wmo/harness/vendor/pi-agent/src/types.ts +428 -0
  186. wmo/harness/vendor/pi-agent/test/agent-loop.test.ts +1351 -0
  187. wmo/harness/vendor/pi-agent/test/agent.test.ts +699 -0
  188. wmo/harness/vendor/pi-agent/test/e2e.test.ts +404 -0
  189. wmo/harness/vendor/pi-agent/test/harness/agent-harness-stream.test.ts +213 -0
  190. wmo/harness/vendor/pi-agent/test/harness/agent-harness.test.ts +608 -0
  191. wmo/harness/vendor/pi-agent/test/harness/compaction.test.ts +655 -0
  192. wmo/harness/vendor/pi-agent/test/harness/nodejs-env.test.ts +321 -0
  193. wmo/harness/vendor/pi-agent/test/harness/prompt-templates.test.ts +90 -0
  194. wmo/harness/vendor/pi-agent/test/harness/repo.test.ts +68 -0
  195. wmo/harness/vendor/pi-agent/test/harness/resource-formatting.test.ts +24 -0
  196. wmo/harness/vendor/pi-agent/test/harness/session-test-utils.ts +55 -0
  197. wmo/harness/vendor/pi-agent/test/harness/session-uuid.test.ts +50 -0
  198. wmo/harness/vendor/pi-agent/test/harness/session.test.ts +156 -0
  199. wmo/harness/vendor/pi-agent/test/harness/skills.test.ts +116 -0
  200. wmo/harness/vendor/pi-agent/test/harness/storage.test.ts +299 -0
  201. wmo/harness/vendor/pi-agent/test/harness/system-prompt.test.ts +66 -0
  202. wmo/harness/vendor/pi-agent/test/harness/truncate.test.ts +169 -0
  203. wmo/harness/vendor/pi-agent/test/scratch/simple.ts +72 -0
  204. wmo/harness/vendor/pi-agent/test/utils/calculate.ts +32 -0
  205. wmo/harness/vendor/pi-agent/test/utils/get-current-time.ts +46 -0
  206. wmo/harness/vendor/pi-agent/tsconfig.build.json +13 -0
  207. wmo/harness/vendor/pi-agent/vitest.config.ts +19 -0
  208. wmo/harness/vendor/pi-agent/vitest.harness.config.ts +28 -0
  209. wmo/harness/vendor/vendor_pi.sh +59 -0
  210. wmo/harness/workspace_patch.py +270 -0
  211. wmo/ingest/__init__.py +47 -0
  212. wmo/ingest/adapter.py +72 -0
  213. wmo/ingest/base.py +114 -0
  214. wmo/ingest/braintrust.py +339 -0
  215. wmo/ingest/detect.py +126 -0
  216. wmo/ingest/langfuse.py +291 -0
  217. wmo/ingest/langsmith.py +444 -0
  218. wmo/ingest/mastra.py +330 -0
  219. wmo/ingest/messages.py +170 -0
  220. wmo/ingest/normalize.py +679 -0
  221. wmo/ingest/otel_genai.py +69 -0
  222. wmo/ingest/otel_writer.py +100 -0
  223. wmo/ingest/phoenix.py +150 -0
  224. wmo/ingest/postgres.py +246 -0
  225. wmo/ingest/posthog.py +320 -0
  226. wmo/ingest/quality.py +28 -0
  227. wmo/ingest/stream.py +209 -0
  228. wmo/ingest/testdata/sample_otlp.json +60 -0
  229. wmo/ingest/testdata/sample_spans.jsonl +3 -0
  230. wmo/optimize/__init__.py +25 -0
  231. wmo/optimize/base.py +143 -0
  232. wmo/optimize/gepa.py +806 -0
  233. wmo/optimize/judge.py +262 -0
  234. wmo/optimize/judge_quality.py +359 -0
  235. wmo/optimize/knn.py +468 -0
  236. wmo/optimize/numeric.py +152 -0
  237. wmo/optimize/outcomes.py +103 -0
  238. wmo/optimize/policy.py +669 -0
  239. wmo/optimize/report.py +231 -0
  240. wmo/optimize/reward.py +129 -0
  241. wmo/optimize/routing.py +373 -0
  242. wmo/platform/__init__.py +6 -0
  243. wmo/platform/auth.py +115 -0
  244. wmo/platform/client.py +551 -0
  245. wmo/platform/credentials.py +126 -0
  246. wmo/platform/transfer.py +158 -0
  247. wmo/providers/__init__.py +40 -0
  248. wmo/providers/_bedrock_chat.py +155 -0
  249. wmo/providers/_openai_common.py +182 -0
  250. wmo/providers/_responses_common.py +472 -0
  251. wmo/providers/anthropic.py +134 -0
  252. wmo/providers/azure_openai.py +296 -0
  253. wmo/providers/base.py +300 -0
  254. wmo/providers/bedrock.py +312 -0
  255. wmo/providers/models.py +205 -0
  256. wmo/providers/openai.py +143 -0
  257. wmo/providers/openai_responses.py +240 -0
  258. wmo/providers/pool.py +170 -0
  259. wmo/providers/registry.py +73 -0
  260. wmo/providers/retry.py +151 -0
  261. wmo/providers/tinker.py +936 -0
  262. wmo/providers/waterfall.py +336 -0
  263. wmo/research/__init__.py +81 -0
  264. wmo/research/ablation.py +133 -0
  265. wmo/research/concurrency_plot.py +523 -0
  266. wmo/research/concurrency_run.py +240 -0
  267. wmo/research/concurrency_scaling.py +270 -0
  268. wmo/research/gepa_scaling.py +274 -0
  269. wmo/research/pipeline.py +198 -0
  270. wmo/research/scaling_split.py +82 -0
  271. wmo/research/scenario_fidelity.py +198 -0
  272. wmo/research/scenario_recovery.py +92 -0
  273. wmo/research/seed_stability.py +90 -0
  274. wmo/research/trace_scaling.py +348 -0
  275. wmo/retrieval/__init__.py +6 -0
  276. wmo/retrieval/embedders.py +105 -0
  277. wmo/retrieval/leakfree.py +52 -0
  278. wmo/retrieval/retriever.py +173 -0
  279. wmo/scenarios/__init__.py +58 -0
  280. wmo/scenarios/builder.py +152 -0
  281. wmo/scenarios/mining/__init__.py +27 -0
  282. wmo/scenarios/mining/clustering.py +171 -0
  283. wmo/scenarios/mining/facets.py +226 -0
  284. wmo/scenarios/mining/selection.py +220 -0
  285. wmo/scenarios/synthesis/__init__.py +6 -0
  286. wmo/scenarios/synthesis/scenario_set.py +63 -0
  287. wmo/scenarios/synthesis/synthesizer.py +85 -0
  288. wmo/scenarios/verification/__init__.py +17 -0
  289. wmo/scenarios/verification/judge.py +97 -0
  290. wmo/scenarios/verification/verify.py +135 -0
  291. wmo/serving/__init__.py +5 -0
  292. wmo/serving/builds.py +451 -0
  293. wmo/serving/chat.py +878 -0
  294. wmo/serving/endpoint_config.py +64 -0
  295. wmo/serving/savings.py +250 -0
  296. wmo/serving/server.py +553 -0
  297. wmo/serving/traces_source.py +206 -0
  298. wmo/telemetry.py +213 -0
  299. wmo/tracking/__init__.py +36 -0
  300. wmo/tracking/clock.py +24 -0
  301. wmo/tracking/metered.py +125 -0
  302. wmo/tracking/pricing.py +99 -0
  303. wmo/tracking/store.py +31 -0
  304. wmo/tracking/tracker.py +149 -0
  305. world_model_optimizer-0.2.0.dist-info/METADATA +203 -0
  306. world_model_optimizer-0.2.0.dist-info/RECORD +308 -0
  307. world_model_optimizer-0.2.0.dist-info/WHEEL +4 -0
  308. world_model_optimizer-0.2.0.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,376 @@
1
+ <!-- Synced from jot qe0ikdqs. Edit this file in-repo going forward. -->
2
+
3
+ # Pi Observability Design Notes
4
+
5
+ ## Goal
6
+
7
+ Make `packages/ai` and `packages/agent`/harness observable without depending on OpenTelemetry, Sentry, or any APM vendor.
8
+
9
+ Pi should emit stable, structured lifecycle events. External listeners can convert those events into OTel spans, Sentry spans, logs, metrics, or custom telemetry.
10
+
11
+ ## Mental model
12
+
13
+ A trace is one causal tree of work, e.g. one user turn.
14
+
15
+ A span is one timed operation in that tree. It is normally represented by IDs, not object pointers:
16
+
17
+ ```ts
18
+ interface SpanRecord {
19
+ traceId: string;
20
+ spanId: string;
21
+ parentSpanId?: string;
22
+ name: string;
23
+ startTime: number;
24
+ endTime?: number;
25
+ attributes: Record<string, unknown>;
26
+ status: "ok" | "error";
27
+ }
28
+ ```
29
+
30
+ Example tree:
31
+
32
+ ```text
33
+ traceId=t1 spanId=s1 parent=- name=pi.agent.prompt
34
+ traceId=t1 spanId=s2 parent=s1 name=pi.agent.turn
35
+ traceId=t1 spanId=s3 parent=s2 name=pi.ai.provider.request
36
+ traceId=t1 spanId=s4 parent=s2 name=pi.agent.tool_call
37
+ traceId=t1 spanId=s5 parent=s4 name=pi.session.append_entry
38
+ ```
39
+
40
+ ## Async context
41
+
42
+ JavaScript has one event loop but multiple async chains can interleave. A single global `currentContext` breaks under concurrency.
43
+
44
+ `AsyncLocalStorage` is the Node equivalent of `ThreadLocal` for async continuations. It lets concurrent operations keep distinct current contexts:
45
+
46
+ ```ts
47
+ await Promise.all([
48
+ runWithPiContext({ userId: "alice" }, () => harness.prompt("A")),
49
+ runWithPiContext({ userId: "bob" }, () => harness.prompt("B")),
50
+ ]);
51
+ ```
52
+
53
+ Deep code can then read the correct current context for the active async chain.
54
+
55
+ Pi must run in Node, Bun, browser, workers, and other JS runtimes, so ALS cannot be the core abstraction. It should be a runtime adapter.
56
+
57
+ ## Core design
58
+
59
+ Pi owns a small runtime-agnostic observability abstraction:
60
+
61
+ ```ts
62
+ export interface PiObservabilityContext {
63
+ traceId?: string;
64
+ currentSpanId?: string;
65
+ userContext?: Record<string, unknown>;
66
+ }
67
+
68
+ export interface PiObservabilityEvent {
69
+ type: "start" | "end" | "error" | "event";
70
+ name: string;
71
+ traceId: string;
72
+ spanId?: string;
73
+ parentSpanId?: string;
74
+ timestamp: number;
75
+ durationMs?: number;
76
+ context?: Record<string, unknown>;
77
+ payload?: Record<string, unknown>;
78
+ error?: { name: string; message: string };
79
+ }
80
+
81
+ export interface PiObservability {
82
+ getContext(): PiObservabilityContext | undefined;
83
+ runWithContext<T>(context: PiObservabilityContext, fn: () => T): T;
84
+ emit(event: PiObservabilityEvent): void;
85
+ hasSubscribers(): boolean;
86
+ }
87
+ ```
88
+
89
+ Public API:
90
+
91
+ ```ts
92
+ export function configurePiObservability(observability: PiObservability): void;
93
+ export function subscribePiObservability(listener: (event: PiObservabilityEvent) => void): () => void;
94
+ export function runWithPiContext<T>(userContext: Record<string, unknown>, fn: () => T): T;
95
+ export function traceOperation<T>(name: string, payload: Record<string, unknown>, fn: () => T): T;
96
+ ```
97
+
98
+ `traceOperation()`:
99
+
100
+ 1. reads the current context
101
+ 2. creates `traceId` if missing
102
+ 3. creates a new `spanId`
103
+ 4. uses current span as `parentSpanId`
104
+ 5. emits `start`
105
+ 6. runs callback under child context
106
+ 7. emits `end` or `error`
107
+ 8. rethrows on error
108
+
109
+ Pseudo-code:
110
+
111
+ ```ts
112
+ function traceOperation<T>(name: string, payload: Record<string, unknown>, fn: () => T): T {
113
+ const parent = getContext();
114
+ const traceId = parent?.traceId ?? createId();
115
+ const spanId = createId();
116
+ const parentSpanId = parent?.currentSpanId;
117
+
118
+ const child = { ...parent, traceId, currentSpanId: spanId };
119
+
120
+ emit({ type: "start", name, traceId, spanId, parentSpanId, timestamp: Date.now(), context: parent?.userContext, payload });
121
+
122
+ return runWithContext(child, () => {
123
+ try {
124
+ const result = fn();
125
+ // Promise-aware implementation emits end/error after settlement.
126
+ emit({ type: "end", name, traceId, spanId, parentSpanId, timestamp: Date.now(), context: child.userContext, payload });
127
+ return result;
128
+ } catch (error) {
129
+ emit({ type: "error", name, traceId, spanId, parentSpanId, timestamp: Date.now(), context: child.userContext, payload, error: serializeError(error) });
130
+ throw error;
131
+ }
132
+ });
133
+ }
134
+ ```
135
+
136
+ ## Runtime adapters
137
+
138
+ Core packages should not import Node-only APIs.
139
+
140
+ Possible implementations:
141
+
142
+ - Node adapter: `AsyncLocalStorage` for context, optional `diagnostics_channel` publishing.
143
+ - Browser/workers fallback: local subscriber set and limited/manual context propagation.
144
+ - Bun/Deno adapters: use runtime-specific async context if available.
145
+
146
+ For Node, diagnostics channels can be used as a passive event bus:
147
+
148
+ ```ts
149
+ import { channel } from "diagnostics_channel";
150
+ channel("pi.observability").publish(event);
151
+ ```
152
+
153
+ Subscribers can create OTel/Sentry spans without monkey-patching pi.
154
+
155
+ ## What pi emits
156
+
157
+ Pi emits what happened. It does not create OTel/Sentry spans directly.
158
+
159
+ Initial minimal event names:
160
+
161
+ ```text
162
+ pi.agent.prompt
163
+ pi.agent.skill
164
+ pi.agent.prompt_template
165
+ pi.agent.compaction
166
+ pi.agent.branch_navigation
167
+ pi.agent.session.append_entry
168
+ pi.ai.provider.request
169
+ ```
170
+
171
+ Each operation emits:
172
+
173
+ ```text
174
+ start
175
+ end
176
+ error
177
+ ```
178
+
179
+ Later additions:
180
+
181
+ ```text
182
+ pi.agent.turn
183
+ pi.agent.tool_call
184
+ pi.agent.queue_update
185
+ pi.ai.provider.retry
186
+ pi.ai.provider.first_token
187
+ pi.ai.provider.usage
188
+ pi.session.read
189
+ pi.session.write
190
+ ```
191
+
192
+ ## Minimal instrumentation points
193
+
194
+ ### packages/agent
195
+
196
+ Wrap:
197
+
198
+ - `AgentHarness.prompt()`
199
+ - `AgentHarness.skill()`
200
+ - `AgentHarness.promptFromTemplate()`
201
+ - `AgentHarness.compact()`
202
+ - `AgentHarness.navigateTree()`
203
+ - `Session.appendTypedEntry()` or storage append facade
204
+
205
+ Example:
206
+
207
+ ```ts
208
+ return traceOperation(
209
+ "pi.agent.prompt",
210
+ {
211
+ sessionId: turnState.sessionId,
212
+ provider: turnState.model.provider,
213
+ model: turnState.model.id,
214
+ promptLength: text.length,
215
+ imageCount: options?.images?.length ?? 0,
216
+ },
217
+ () => this.executeTurn(turnState, text, options),
218
+ );
219
+ ```
220
+
221
+ Session write:
222
+
223
+ ```ts
224
+ return traceOperation(
225
+ "pi.agent.session.append_entry",
226
+ { entryType: entry.type },
227
+ async () => {
228
+ await this.unwrap(this.storage.appendEntry(entry));
229
+ return entry.id;
230
+ },
231
+ );
232
+ ```
233
+
234
+ ### packages/ai
235
+
236
+ Wrap common provider boundaries:
237
+
238
+ - `streamSimple()`
239
+ - `completeSimple()`
240
+
241
+ Example:
242
+
243
+ ```ts
244
+ return traceOperation(
245
+ "pi.ai.provider.request",
246
+ {
247
+ api: model.api,
248
+ provider: model.provider,
249
+ model: model.id,
250
+ sessionId: options.sessionId,
251
+ reasoning: options.reasoning,
252
+ },
253
+ () => actualStreamSimple(model, context, options),
254
+ );
255
+ ```
256
+
257
+ End/error payloads can include safe metadata:
258
+
259
+ - stop reason
260
+ - status code
261
+ - retry count
262
+ - input/output/total tokens
263
+ - cost total
264
+ - aborted/timeout flag
265
+
266
+ ## Safety and redaction
267
+
268
+ Default payloads must be safe.
269
+
270
+ Safe by default:
271
+
272
+ - provider
273
+ - model
274
+ - API identifier
275
+ - session id
276
+ - entry type
277
+ - tool name
278
+ - status code
279
+ - stop reason
280
+ - token counts
281
+ - costs
282
+ - durations
283
+
284
+ Unsafe by default:
285
+
286
+ - prompts
287
+ - completions
288
+ - tool args
289
+ - tool results
290
+ - shell output
291
+ - file contents
292
+ - provider request payloads
293
+ - provider response bodies
294
+ - API keys
295
+ - headers
296
+
297
+ Content capture can be opt-in later with explicit redaction hooks.
298
+
299
+ ## Listener behavior
300
+
301
+ Observability must never affect pi execution.
302
+
303
+ Subscriber errors should be swallowed or isolated. Harness hooks are control-plane and may affect execution; observability subscribers are passive and must not.
304
+
305
+ ## User context
306
+
307
+ Users can associate arbitrary context with a turn:
308
+
309
+ ```ts
310
+ await runWithPiContext(
311
+ {
312
+ userId: "u123",
313
+ orgId: "acme",
314
+ region: "eu",
315
+ },
316
+ () => harness.prompt("fix this"),
317
+ );
318
+ ```
319
+
320
+ Every emitted event inside that async chain includes the context:
321
+
322
+ ```ts
323
+ {
324
+ type: "start",
325
+ name: "pi.ai.provider.request",
326
+ traceId: "t1",
327
+ spanId: "s3",
328
+ parentSpanId: "s1",
329
+ context: {
330
+ userId: "u123",
331
+ orgId: "acme",
332
+ region: "eu",
333
+ },
334
+ payload: {
335
+ provider: "anthropic",
336
+ model: "claude-sonnet-4",
337
+ },
338
+ }
339
+ ```
340
+
341
+ An OTel adapter can map this to span attributes. A Sentry adapter can map it to Sentry context/spans. A custom user can log JSON.
342
+
343
+ ## Package story
344
+
345
+ Minimal initial package:
346
+
347
+ ```text
348
+ packages/observability
349
+ runtime-agnostic context + traceOperation + subscribe
350
+ ```
351
+
352
+ Then:
353
+
354
+ ```text
355
+ packages/ai
356
+ emits pi.ai.* events
357
+
358
+ packages/agent
359
+ emits pi.agent.* / pi.session.* events
360
+ ```
361
+
362
+ Optional later:
363
+
364
+ ```text
365
+ packages/observability-node
366
+ AsyncLocalStorage + diagnostics_channel bridge
367
+
368
+ packages/otel
369
+ subscribes to pi events and creates OpenTelemetry spans
370
+ ```
371
+
372
+ ## Thesis
373
+
374
+ Pi defines a stable, safe event contract. Adapters define where events go.
375
+
376
+ This makes ai/harness observable without binding core packages to OTel, Sentry, Node-only APIs, or monkey-patching.
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@earendil-works/pi-agent-core",
3
+ "version": "0.80.3",
4
+ "description": "General-purpose agent with transport abstraction, state management, and attachment support",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ },
13
+ "./node": {
14
+ "types": "./dist/node.d.ts",
15
+ "import": "./dist/node.js"
16
+ },
17
+ "./package.json": "./package.json"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "README.md"
22
+ ],
23
+ "scripts": {
24
+ "clean": "shx rm -rf dist",
25
+ "build": "tsgo -p tsconfig.build.json",
26
+ "test": "vitest --run",
27
+ "test:harness": "vitest --run --config vitest.harness.config.ts",
28
+ "coverage:harness": "vitest --run --config vitest.harness.config.ts --coverage",
29
+ "prepublishOnly": "npm run clean && npm run build"
30
+ },
31
+ "dependencies": {
32
+ "@earendil-works/pi-ai": "^0.80.3",
33
+ "ignore": "7.0.5",
34
+ "typebox": "1.1.38",
35
+ "yaml": "2.9.0"
36
+ },
37
+ "keywords": [
38
+ "ai",
39
+ "agent",
40
+ "llm",
41
+ "transport",
42
+ "state-management"
43
+ ],
44
+ "author": "Mario Zechner",
45
+ "license": "MIT",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "git+https://github.com/earendil-works/pi.git",
49
+ "directory": "packages/agent"
50
+ },
51
+ "engines": {
52
+ "node": ">=22.19.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "24.12.4",
56
+ "@vitest/coverage-v8": "4.1.9",
57
+ "typescript": "5.9.3",
58
+ "vitest": "4.1.9"
59
+ }
60
+ }