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.
- llm_waterfall/LICENSE +21 -0
- llm_waterfall/__init__.py +53 -0
- llm_waterfall/adapters/__init__.py +36 -0
- llm_waterfall/adapters/anthropic.py +105 -0
- llm_waterfall/adapters/aws_mantle.py +47 -0
- llm_waterfall/adapters/azure_openai.py +71 -0
- llm_waterfall/adapters/base.py +51 -0
- llm_waterfall/adapters/bedrock.py +309 -0
- llm_waterfall/adapters/openai.py +130 -0
- llm_waterfall/classify.py +184 -0
- llm_waterfall/pricing.py +110 -0
- llm_waterfall/py.typed +0 -0
- llm_waterfall/types.py +295 -0
- llm_waterfall/waterfall.py +255 -0
- wmo/__init__.py +38 -0
- wmo/agents/__init__.py +7 -0
- wmo/agents/default.py +29 -0
- wmo/agents/meta.py +55 -0
- wmo/agents/optimizer.py +55 -0
- wmo/agents/project.py +928 -0
- wmo/cli/__init__.py +5 -0
- wmo/cli/agent_session.py +1123 -0
- wmo/cli/app.py +2489 -0
- wmo/cli/e2b_cmds.py +212 -0
- wmo/cli/eval_closed_loop.py +207 -0
- wmo/cli/harness_app.py +1147 -0
- wmo/cli/harness_distill.py +659 -0
- wmo/cli/hosted_session.py +880 -0
- wmo/cli/ingest_cmd.py +165 -0
- wmo/cli/model_roles.py +82 -0
- wmo/cli/platform_cmds.py +372 -0
- wmo/cli/route_app.py +274 -0
- wmo/cli/session_state.py +243 -0
- wmo/cli/ui.py +1107 -0
- wmo/cli/workspace_sync.py +504 -0
- wmo/config/__init__.py +60 -0
- wmo/config/card.py +129 -0
- wmo/config/config.py +367 -0
- wmo/config/dotenv.py +67 -0
- wmo/config/settings.py +128 -0
- wmo/config/store.py +177 -0
- wmo/conftest.py +19 -0
- wmo/connect/__init__.py +88 -0
- wmo/connect/apps.py +78 -0
- wmo/connect/brave.py +284 -0
- wmo/connect/connector.py +79 -0
- wmo/connect/credentials.py +164 -0
- wmo/connect/github.py +321 -0
- wmo/connect/google.py +627 -0
- wmo/connect/notion.py +790 -0
- wmo/connect/oauth.py +461 -0
- wmo/connect/slack.py +555 -0
- wmo/connect/store.py +199 -0
- wmo/connect/types.py +156 -0
- wmo/core/__init__.py +21 -0
- wmo/core/parsing.py +281 -0
- wmo/core/render.py +271 -0
- wmo/core/text.py +40 -0
- wmo/core/types.py +116 -0
- wmo/distill/__init__.py +14 -0
- wmo/distill/agents.py +140 -0
- wmo/distill/config.py +1006 -0
- wmo/distill/cost.py +437 -0
- wmo/distill/data.py +921 -0
- wmo/distill/deadlines.py +254 -0
- wmo/distill/fake_tinker.py +734 -0
- wmo/distill/gate.py +122 -0
- wmo/distill/loop.py +3499 -0
- wmo/distill/renderers.py +399 -0
- wmo/distill/rendering.py +620 -0
- wmo/distill/rollouts.py +726 -0
- wmo/distill/samples.py +195 -0
- wmo/distill/store.py +829 -0
- wmo/distill/teacher.py +714 -0
- wmo/distill/tokens.py +535 -0
- wmo/distill/tracking.py +552 -0
- wmo/distill/tripwire.py +411 -0
- wmo/distill/xtoken/byte_offsets.py +152 -0
- wmo/distill/xtoken/chunks.py +457 -0
- wmo/distill/xtoken/prompt_logprobs.py +475 -0
- wmo/distill/xtoken/teacher_render.py +346 -0
- wmo/engine/__init__.py +28 -0
- wmo/engine/autoconfig.py +367 -0
- wmo/engine/build.py +346 -0
- wmo/engine/demo.py +77 -0
- wmo/engine/eval_suites.py +245 -0
- wmo/engine/grounding.py +491 -0
- wmo/engine/knowledge.py +291 -0
- wmo/engine/loader.py +36 -0
- wmo/engine/play.py +92 -0
- wmo/engine/prompts.py +99 -0
- wmo/engine/replay.py +443 -0
- wmo/engine/reporting.py +58 -0
- wmo/engine/workspace.py +468 -0
- wmo/engine/world_model.py +568 -0
- wmo/env/__init__.py +22 -0
- wmo/env/base.py +121 -0
- wmo/env/closed_loop.py +229 -0
- wmo/env/episode.py +107 -0
- wmo/env/llm_agent.py +93 -0
- wmo/env/scenarios.py +73 -0
- wmo/evals/__init__.py +52 -0
- wmo/evals/agreement.py +110 -0
- wmo/evals/base.py +45 -0
- wmo/evals/closed_loop.py +480 -0
- wmo/evals/failover.py +96 -0
- wmo/evals/gold.py +127 -0
- wmo/evals/grid.py +394 -0
- wmo/evals/grid_plot.py +205 -0
- wmo/evals/harbor/__init__.py +27 -0
- wmo/evals/harbor/agent.py +573 -0
- wmo/evals/harbor/ctrf.py +171 -0
- wmo/evals/harbor/e2b_environment.py +587 -0
- wmo/evals/harbor/e2b_template_policy.py +144 -0
- wmo/evals/harbor/scorer.py +875 -0
- wmo/evals/harbor/tasks.py +140 -0
- wmo/evals/open_loop.py +194 -0
- wmo/evals/tasks.py +53 -0
- wmo/harness/__init__.py +51 -0
- wmo/harness/code_runtime.py +288 -0
- wmo/harness/create.py +1191 -0
- wmo/harness/delta.py +220 -0
- wmo/harness/doc.py +556 -0
- wmo/harness/e2b_ledger.py +342 -0
- wmo/harness/e2b_reap.py +476 -0
- wmo/harness/e2b_sandbox.py +350 -0
- wmo/harness/environment.py +35 -0
- wmo/harness/live_session.py +543 -0
- wmo/harness/mutate.py +343 -0
- wmo/harness/pi_e2b.py +1710 -0
- wmo/harness/pi_entry/entry.ts +268 -0
- wmo/harness/pi_entry/runner_frames.ts +92 -0
- wmo/harness/pi_entry/runner_live.ts +587 -0
- wmo/harness/pi_entry/runner_service.ts +270 -0
- wmo/harness/pi_entry/runner_stdio.ts +374 -0
- wmo/harness/pi_entry/runner_termination.ts +142 -0
- wmo/harness/pi_local.py +262 -0
- wmo/harness/pi_runtime.py +495 -0
- wmo/harness/pi_vendor.py +65 -0
- wmo/harness/population.py +509 -0
- wmo/harness/project_proposer.py +569 -0
- wmo/harness/proposer.py +977 -0
- wmo/harness/runner_link.py +619 -0
- wmo/harness/runtime.py +389 -0
- wmo/harness/scoring.py +247 -0
- wmo/harness/skills.py +116 -0
- wmo/harness/source_tree.py +319 -0
- wmo/harness/store.py +176 -0
- wmo/harness/tools.py +105 -0
- wmo/harness/vendor/manifest.sha256 +58 -0
- wmo/harness/vendor/pi-agent/CHANGELOG.md +556 -0
- wmo/harness/vendor/pi-agent/LICENSE +21 -0
- wmo/harness/vendor/pi-agent/README.md +488 -0
- wmo/harness/vendor/pi-agent/VENDOR.md +39 -0
- wmo/harness/vendor/pi-agent/docs/agent-harness.md +486 -0
- wmo/harness/vendor/pi-agent/docs/durable-harness.md +212 -0
- wmo/harness/vendor/pi-agent/docs/hooks.md +445 -0
- wmo/harness/vendor/pi-agent/docs/models.md +966 -0
- wmo/harness/vendor/pi-agent/docs/observability.md +376 -0
- wmo/harness/vendor/pi-agent/package.json +60 -0
- wmo/harness/vendor/pi-agent/src/agent-loop.ts +748 -0
- wmo/harness/vendor/pi-agent/src/agent.ts +575 -0
- wmo/harness/vendor/pi-agent/src/harness/agent-harness.ts +1029 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/branch-summarization.ts +261 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/compaction.ts +747 -0
- wmo/harness/vendor/pi-agent/src/harness/compaction/utils.ts +144 -0
- wmo/harness/vendor/pi-agent/src/harness/env/nodejs.ts +550 -0
- wmo/harness/vendor/pi-agent/src/harness/messages.ts +164 -0
- wmo/harness/vendor/pi-agent/src/harness/prompt-templates.ts +267 -0
- wmo/harness/vendor/pi-agent/src/harness/session/jsonl-repo.ts +177 -0
- wmo/harness/vendor/pi-agent/src/harness/session/jsonl-storage.ts +293 -0
- wmo/harness/vendor/pi-agent/src/harness/session/memory-repo.ts +50 -0
- wmo/harness/vendor/pi-agent/src/harness/session/memory-storage.ts +131 -0
- wmo/harness/vendor/pi-agent/src/harness/session/repo-utils.ts +51 -0
- wmo/harness/vendor/pi-agent/src/harness/session/session.ts +267 -0
- wmo/harness/vendor/pi-agent/src/harness/session/uuid.ts +54 -0
- wmo/harness/vendor/pi-agent/src/harness/skills.ts +375 -0
- wmo/harness/vendor/pi-agent/src/harness/system-prompt.ts +34 -0
- wmo/harness/vendor/pi-agent/src/harness/types.ts +836 -0
- wmo/harness/vendor/pi-agent/src/harness/utils/shell-output.ts +135 -0
- wmo/harness/vendor/pi-agent/src/harness/utils/truncate.ts +344 -0
- wmo/harness/vendor/pi-agent/src/index.ts +44 -0
- wmo/harness/vendor/pi-agent/src/node.ts +2 -0
- wmo/harness/vendor/pi-agent/src/proxy.ts +367 -0
- wmo/harness/vendor/pi-agent/src/types.ts +428 -0
- wmo/harness/vendor/pi-agent/test/agent-loop.test.ts +1351 -0
- wmo/harness/vendor/pi-agent/test/agent.test.ts +699 -0
- wmo/harness/vendor/pi-agent/test/e2e.test.ts +404 -0
- wmo/harness/vendor/pi-agent/test/harness/agent-harness-stream.test.ts +213 -0
- wmo/harness/vendor/pi-agent/test/harness/agent-harness.test.ts +608 -0
- wmo/harness/vendor/pi-agent/test/harness/compaction.test.ts +655 -0
- wmo/harness/vendor/pi-agent/test/harness/nodejs-env.test.ts +321 -0
- wmo/harness/vendor/pi-agent/test/harness/prompt-templates.test.ts +90 -0
- wmo/harness/vendor/pi-agent/test/harness/repo.test.ts +68 -0
- wmo/harness/vendor/pi-agent/test/harness/resource-formatting.test.ts +24 -0
- wmo/harness/vendor/pi-agent/test/harness/session-test-utils.ts +55 -0
- wmo/harness/vendor/pi-agent/test/harness/session-uuid.test.ts +50 -0
- wmo/harness/vendor/pi-agent/test/harness/session.test.ts +156 -0
- wmo/harness/vendor/pi-agent/test/harness/skills.test.ts +116 -0
- wmo/harness/vendor/pi-agent/test/harness/storage.test.ts +299 -0
- wmo/harness/vendor/pi-agent/test/harness/system-prompt.test.ts +66 -0
- wmo/harness/vendor/pi-agent/test/harness/truncate.test.ts +169 -0
- wmo/harness/vendor/pi-agent/test/scratch/simple.ts +72 -0
- wmo/harness/vendor/pi-agent/test/utils/calculate.ts +32 -0
- wmo/harness/vendor/pi-agent/test/utils/get-current-time.ts +46 -0
- wmo/harness/vendor/pi-agent/tsconfig.build.json +13 -0
- wmo/harness/vendor/pi-agent/vitest.config.ts +19 -0
- wmo/harness/vendor/pi-agent/vitest.harness.config.ts +28 -0
- wmo/harness/vendor/vendor_pi.sh +59 -0
- wmo/harness/workspace_patch.py +270 -0
- wmo/ingest/__init__.py +47 -0
- wmo/ingest/adapter.py +72 -0
- wmo/ingest/base.py +114 -0
- wmo/ingest/braintrust.py +339 -0
- wmo/ingest/detect.py +126 -0
- wmo/ingest/langfuse.py +291 -0
- wmo/ingest/langsmith.py +444 -0
- wmo/ingest/mastra.py +330 -0
- wmo/ingest/messages.py +170 -0
- wmo/ingest/normalize.py +679 -0
- wmo/ingest/otel_genai.py +69 -0
- wmo/ingest/otel_writer.py +100 -0
- wmo/ingest/phoenix.py +150 -0
- wmo/ingest/postgres.py +246 -0
- wmo/ingest/posthog.py +320 -0
- wmo/ingest/quality.py +28 -0
- wmo/ingest/stream.py +209 -0
- wmo/ingest/testdata/sample_otlp.json +60 -0
- wmo/ingest/testdata/sample_spans.jsonl +3 -0
- wmo/optimize/__init__.py +25 -0
- wmo/optimize/base.py +143 -0
- wmo/optimize/gepa.py +806 -0
- wmo/optimize/judge.py +262 -0
- wmo/optimize/judge_quality.py +359 -0
- wmo/optimize/knn.py +468 -0
- wmo/optimize/numeric.py +152 -0
- wmo/optimize/outcomes.py +103 -0
- wmo/optimize/policy.py +669 -0
- wmo/optimize/report.py +231 -0
- wmo/optimize/reward.py +129 -0
- wmo/optimize/routing.py +373 -0
- wmo/platform/__init__.py +6 -0
- wmo/platform/auth.py +115 -0
- wmo/platform/client.py +551 -0
- wmo/platform/credentials.py +126 -0
- wmo/platform/transfer.py +158 -0
- wmo/providers/__init__.py +40 -0
- wmo/providers/_bedrock_chat.py +155 -0
- wmo/providers/_openai_common.py +182 -0
- wmo/providers/_responses_common.py +472 -0
- wmo/providers/anthropic.py +134 -0
- wmo/providers/azure_openai.py +296 -0
- wmo/providers/base.py +300 -0
- wmo/providers/bedrock.py +312 -0
- wmo/providers/models.py +205 -0
- wmo/providers/openai.py +143 -0
- wmo/providers/openai_responses.py +240 -0
- wmo/providers/pool.py +170 -0
- wmo/providers/registry.py +73 -0
- wmo/providers/retry.py +151 -0
- wmo/providers/tinker.py +936 -0
- wmo/providers/waterfall.py +336 -0
- wmo/research/__init__.py +81 -0
- wmo/research/ablation.py +133 -0
- wmo/research/concurrency_plot.py +523 -0
- wmo/research/concurrency_run.py +240 -0
- wmo/research/concurrency_scaling.py +270 -0
- wmo/research/gepa_scaling.py +274 -0
- wmo/research/pipeline.py +198 -0
- wmo/research/scaling_split.py +82 -0
- wmo/research/scenario_fidelity.py +198 -0
- wmo/research/scenario_recovery.py +92 -0
- wmo/research/seed_stability.py +90 -0
- wmo/research/trace_scaling.py +348 -0
- wmo/retrieval/__init__.py +6 -0
- wmo/retrieval/embedders.py +105 -0
- wmo/retrieval/leakfree.py +52 -0
- wmo/retrieval/retriever.py +173 -0
- wmo/scenarios/__init__.py +58 -0
- wmo/scenarios/builder.py +152 -0
- wmo/scenarios/mining/__init__.py +27 -0
- wmo/scenarios/mining/clustering.py +171 -0
- wmo/scenarios/mining/facets.py +226 -0
- wmo/scenarios/mining/selection.py +220 -0
- wmo/scenarios/synthesis/__init__.py +6 -0
- wmo/scenarios/synthesis/scenario_set.py +63 -0
- wmo/scenarios/synthesis/synthesizer.py +85 -0
- wmo/scenarios/verification/__init__.py +17 -0
- wmo/scenarios/verification/judge.py +97 -0
- wmo/scenarios/verification/verify.py +135 -0
- wmo/serving/__init__.py +5 -0
- wmo/serving/builds.py +451 -0
- wmo/serving/chat.py +878 -0
- wmo/serving/endpoint_config.py +64 -0
- wmo/serving/savings.py +250 -0
- wmo/serving/server.py +553 -0
- wmo/serving/traces_source.py +206 -0
- wmo/telemetry.py +213 -0
- wmo/tracking/__init__.py +36 -0
- wmo/tracking/clock.py +24 -0
- wmo/tracking/metered.py +125 -0
- wmo/tracking/pricing.py +99 -0
- wmo/tracking/store.py +31 -0
- wmo/tracking/tracker.py +149 -0
- world_model_optimizer-0.2.0.dist-info/METADATA +203 -0
- world_model_optimizer-0.2.0.dist-info/RECORD +308 -0
- world_model_optimizer-0.2.0.dist-info/WHEEL +4 -0
- 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
|
+
}
|