Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions apps/website/content/AGENTS.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ See https://threadplane.ai/privacy.


Supported runtime/browser collection is automatic only in Angular development mode.
Production builds, SSR, imports, unused construction, and automated browsers
reporting `navigator.webdriver` are inert. It sends closed
Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session;
milestones are reported only when the runtime is actually used. It sends closed
progress milestones with package/version and random browser-origin/session IDs, never
conversation content or private URLs. Adapter `telemetry: false` disables it; a custom
sink replaces the automatic destination, including nested chat JSON rendering. Use
Expand Down
6 changes: 4 additions & 2 deletions apps/website/content/CLAUDE.md.template
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ See https://threadplane.ai/privacy.


Supported runtime/browser collection is automatic only in Angular development mode.
Production builds, SSR, imports, unused construction, and automated browsers
reporting `navigator.webdriver` are inert. It sends closed
Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session;
milestones are reported only when the runtime is actually used. It sends closed
progress milestones with package/version and random browser-origin/session IDs, never
conversation content or private URLs. Adapter `telemetry: false` disables it; a custom
sink replaces the automatic destination, including nested chat JSON rendering. Use
Expand Down
6 changes: 4 additions & 2 deletions apps/website/public/AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ See https://threadplane.ai/privacy.


Supported runtime/browser collection is automatic only in Angular development mode.
Production builds, SSR, imports, unused construction, and automated browsers
reporting `navigator.webdriver` are inert. It sends closed
Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session;
milestones are reported only when the runtime is actually used. It sends closed
progress milestones with package/version and random browser-origin/session IDs, never
conversation content or private URLs. Adapter `telemetry: false` disables it; a custom
sink replaces the automatic destination, including nested chat JSON rendering. Use
Expand Down
6 changes: 4 additions & 2 deletions apps/website/public/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ See https://threadplane.ai/privacy.


Supported runtime/browser collection is automatic only in Angular development mode.
Production builds, SSR, imports, unused construction, and automated browsers
reporting `navigator.webdriver` are inert. It sends closed
Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session;
milestones are reported only when the runtime is actually used. It sends closed
progress milestones with package/version and random browser-origin/session IDs, never
conversation content or private URLs. Adapter `telemetry: false` disables it; a custom
sink replaces the automatic destination, including nested chat JSON rendering. Use
Expand Down
8 changes: 5 additions & 3 deletions libs/ag-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,9 +235,11 @@ MIT. See [LICENSE](../../LICENSE).
## Development browser collection

Supported LangGraph/AG-UI runtime use and real JSON-render component mounts automatically
report development progress to Threadplane. Angular development mode and browser APIs
are required. Production builds, SSR, imports, unused adapter construction, and
automated browsers reporting `navigator.webdriver` are inert.
report development progress to Threadplane. Angular development mode and browser APIs are
required. Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session; milestones
are reported only when the runtime is actually used.
Reports contain package/version, integration, closed milestones, timestamps, a random
browser-origin ID, and a session with a 30-minute inactivity boundary. They exclude
prompts, messages, application state, private URLs, thread/run IDs, and credentials.
Expand Down
8 changes: 5 additions & 3 deletions libs/ag-ui/src/lib/to-agent.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,16 @@ describe('automatic development evidence', () => {
expect(isDevelopmentRuntimeEnabled(agent)).toBe(telemetry === undefined);
}
});
it('requires a current RUN_FINISHED success, and ignores construction and empty close', async () => {
it('reports a session on construction and requires a current RUN_FINISHED success', async () => {
developmentEvidence.events = []; developmentEvidence.touches = 0;
const stub = new StubAgent();
const agent = toAgent(stub as unknown as AbstractAgent);
expect(developmentEvidence.touches).toBe(0);
await agent.submit({});
expect(developmentEvidence.touches).toBe(1);
expect(developmentEvidence.events).toEqual([]);
await agent.submit({});
// construction plus exactly one beginRun per submit
expect(developmentEvidence.touches).toBe(2);
expect(developmentEvidence.events).toEqual([]);
stub.runAgent.mockImplementationOnce(async () => {
stub.emit({ type: 'UNKNOWN' } as BaseEvent);
expect(developmentEvidence.events).toEqual([]);
Expand Down
2 changes: 2 additions & 0 deletions libs/ag-ui/src/lib/to-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ function createAgentAdapter(
installationToken: (typeof ngDevMode === 'undefined' || ngDevMode) && isDevMode() ? installationToken : null,
enabled: () => options.telemetry === undefined,
});
// One session observation per boot; guards and dedupe live inside touch().
developmentRuntime.touch();
interface AdapterRun extends ReducerDeliveryRun {
startedAt: number;
telemetrySettled: boolean;
Expand Down
8 changes: 5 additions & 3 deletions libs/chat/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,11 @@ MIT. See [LICENSE.md](./LICENSE.md).
## Development browser collection

Supported LangGraph/AG-UI runtime use and real JSON-render component mounts automatically
report development progress to Threadplane. Angular development mode and browser APIs
are required. Production builds, SSR, imports, unused adapter construction, and
automated browsers reporting `navigator.webdriver` are inert.
report development progress to Threadplane. Angular development mode and browser APIs are
required. Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session; milestones
are reported only when the runtime is actually used.
Reports contain package/version, integration, closed milestones, timestamps, a random
browser-origin ID, and a session with a 30-minute inactivity boundary. They exclude
prompts, messages, application state, private URLs, thread/run IDs, and credentials.
Expand Down
8 changes: 5 additions & 3 deletions libs/langgraph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -252,9 +252,11 @@ MIT. See [LICENSE](../../LICENSE).
## Development browser collection

Supported LangGraph/AG-UI runtime use and real JSON-render component mounts automatically
report development progress to Threadplane. Angular development mode and browser APIs
are required. Production builds, SSR, imports, unused adapter construction, and
automated browsers reporting `navigator.webdriver` are inert.
report development progress to Threadplane. Angular development mode and browser APIs are
required. Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session; milestones
are reported only when the runtime is actually used.
Reports contain package/version, integration, closed milestones, timestamps, a random
browser-origin ID, and a session with a 30-minute inactivity boundary. They exclude
prompts, messages, application state, private URLs, thread/run IDs, and credentials.
Expand Down
11 changes: 9 additions & 2 deletions libs/langgraph/src/lib/internals/stream-manager.bridge.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,20 @@ describe('automatic development evidence', () => {
return { transport, subjects, destroy$, bridge };
}

it('reports a session on construction before any request', () => {
const { destroy$ } = setup();
expect(developmentEvidence.touches).toBe(1);
expect(developmentEvidence.events).toEqual([]);
destroy$.next();
expect(developmentEvidence.disposed).toBe(1);
});

it('requires root terminal evidence and disposes with the bridge', async () => {
const { transport, bridge, destroy$ } = setup();
expect(developmentEvidence.touches).toBe(0);
const run = bridge.submit({});
transport.emit([{ type: 'values', data: { done: true } }]); transport.close();
await run;
expect(developmentEvidence.touches).toBeGreaterThan(0);
expect(developmentEvidence.touches).toBeGreaterThan(1);
expect(developmentEvidence.events).toContain('transport.connected');
expect(developmentEvidence.events).toContain('runtime.first_stream_completed');
destroy$.next();
Expand Down
3 changes: 3 additions & 0 deletions libs/langgraph/src/lib/internals/stream-manager.bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,9 @@ export function createStreamManagerBridge<T, ResolvedBag extends BagTemplate = B
installationToken: (typeof ngDevMode === 'undefined' || ngDevMode) && isDevMode() ? installationToken : null,
enabled: () => options.telemetry === undefined,
});
// One session observation per boot. touch() carries every guard and the
// per-session dedupe, so this is inert in production, automation and SSR.
developmentRuntime.touch();
// Intercept onThreadId so currentThreadId tracks a thread the DEFAULT
// transport auto-creates. Without this, each submit() would create a new
// thread because currentThreadId stays null. This wrapper only reaches the
Expand Down
8 changes: 5 additions & 3 deletions libs/render/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,11 @@ MIT. See [LICENSE](../../LICENSE).
## Development browser collection

Supported LangGraph/AG-UI runtime use and real JSON-render component mounts automatically
report development progress to Threadplane. Angular development mode and browser APIs
are required. Production builds, SSR, imports, unused adapter construction, and
automated browsers reporting `navigator.webdriver` are inert.
report development progress to Threadplane. Angular development mode and browser APIs are
required. Production builds, SSR, imports, and automated browsers reporting
`navigator.webdriver` are inert. Creating an agent (or a render element) in a
development-mode browser reports one session start per integration per session; milestones
are reported only when the runtime is actually used.
Reports contain package/version, integration, closed milestones, timestamps, a random
browser-origin ID, and a session with a 30-minute inactivity boundary. They exclude
prompts, messages, application state, private URLs, thread/run IDs, and credentials.
Expand Down
22 changes: 21 additions & 1 deletion libs/render/src/lib/development-mount.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@ class FallbackComponent {}

describe('development generative UI mount evidence', () => {
let mounted: ReturnType<typeof vi.fn>;
let touched: ReturnType<typeof vi.fn>;
beforeEach(() => {
mounted = vi.fn();
touched = vi.fn();
vi.spyOn(telemetry, 'createDevelopmentRuntime').mockImplementation(
(options) => ({
touch: vi.fn(),
touch: () => {
if (options.enabled?.() !== false) touched();
},
dispose: vi.fn(),
milestone: (kind) => {
if (options.enabled?.() !== false) mounted(kind);
Expand Down Expand Up @@ -95,6 +99,7 @@ describe('development generative UI mount evidence', () => {
fx.componentRef.setInput('telemetry', false);
fx.detectChanges();
expect(mounted).not.toHaveBeenCalled();
expect(touched).not.toHaveBeenCalled();
});
it('honors provideRender telemetry false', () => {
TestBed.configureTestingModule({
Expand All @@ -103,5 +108,20 @@ describe('development generative UI mount evidence', () => {
const fx = fixture(spec());
fx.detectChanges();
expect(mounted).not.toHaveBeenCalled();
expect(touched).not.toHaveBeenCalled();
});
it('reports a session when the element is constructed, even when nothing mounts', () => {
const fx = fixture(spec({ type: 'Unknown' }));
fx.detectChanges();
expect(touched).toHaveBeenCalledTimes(1);
expect(mounted).not.toHaveBeenCalled();
fx.detectChanges();
expect(touched).toHaveBeenCalledTimes(1);
expect(mounted).not.toHaveBeenCalled();
});
it('does not report a session when the collection policy is disabled', () => {
const fx = fixture(spec(), false);
fx.detectChanges();
expect(touched).not.toHaveBeenCalled();
});
});
2 changes: 2 additions & 0 deletions libs/render/src/lib/render-element.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,8 @@ export class RenderElementComponent implements OnInit {
private destroyed = false;

constructor() {
// One session observation per boot; guards and dedupe live inside touch().
this.development.touch();
this.destroyRef.onDestroy(() => this.development.dispose());
afterEveryRender(() => {
// Evidence is the mounted outlet itself: an element that is hidden,
Expand Down
14 changes: 8 additions & 6 deletions libs/telemetry/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ retains its own inert install and explicit helper behavior.

## Automatic development runtime collection

LangGraph and AG-UI adapters and the supported JSON renderer use this package's
lazy development collector when they are actually used. Angular's `isDevMode()`
must be true and browser APIs must be available before identity/storage/network
work. Production builds, SSR, imports, unused runtime construction, and automated
browsers reporting `navigator.webdriver` are inert.
A development build served on a remote hostname is still development software.
LangGraph and AG-UI adapters and the supported JSON renderer use this package's lazy
development collector when they are constructed and used. Angular's `isDevMode()` must
be true and browser APIs must be available before identity/storage/network work.
Production builds, SSR, imports, and automated browsers reporting `navigator.webdriver`
are inert. Creating an agent (or a render element) in a development-mode browser reports
one session start per integration per session; milestones are reported only when the
runtime is actually used. A development build served on a remote hostname is still
development software.

Events contain random event IDs, a browser-origin UUID, an inactivity session UUID,
package/version, integration, timestamps, closed progress milestones, and an optional
Expand Down
1 change: 1 addition & 0 deletions libs/telemetry/scripts/verify-angular-install-bridge.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ async function exerciseBundle(
TransformStream,
DOMException,
queueMicrotask,
structuredClone,
crypto: globalThis.crypto,
console: {
info: () => undefined,
Expand Down
2 changes: 1 addition & 1 deletion libs/telemetry/src/browser/development/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function browserAllowed(): boolean {
typeof fetch === 'function'
);
}
/** Inert until a supported integration is actually used; never initialize this at module import. */
/** Inert until an integration calls touch() or reports a milestone; never initialize this at module import. */
export function createDevelopmentRuntime(
options: DevelopmentRuntimeOptions
): DevelopmentRuntime {
Expand Down
Loading