@poncho-ai/harness 0.32.1 → 0.33.0

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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @poncho-ai/harness@0.32.1 build /Users/cesar/Dev/latitude/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.33.0 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
3
3
  > node scripts/embed-docs.js && tsup src/index.ts --format esm --dts
4
4
 
5
5
  [embed-docs] Generated poncho-docs.ts with 4 topics
@@ -8,8 +8,8 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 341.29 KB
12
- ESM ⚡️ Build success in 66ms
11
+ ESM dist/index.js 334.17 KB
12
+ ESM ⚡️ Build success in 152ms
13
13
  DTS Build start
14
- DTS ⚡️ Build success in 3395ms
15
- DTS dist/index.d.ts 34.66 KB
14
+ DTS ⚡️ Build success in 7104ms
15
+ DTS dist/index.d.ts 33.55 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.33.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#75](https://github.com/cesr/poncho-ai/pull/75) [`d447d0a`](https://github.com/cesr/poncho-ai/commit/d447d0a3cb77f3d097276b524b5f870dddf1899e) Thanks [@cesr](https://github.com/cesr)! - Add `maxRuns` option to cron jobs for automatic pruning of old conversations, preventing unbounded storage growth on hosted stores.
8
+
3
9
  ## 0.32.1
4
10
 
5
11
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -20,6 +20,7 @@ interface CronJobConfig {
20
20
  task: string;
21
21
  timezone?: string;
22
22
  channel?: string;
23
+ maxRuns?: number;
23
24
  }
24
25
  interface AgentFrontmatter {
25
26
  name: string;
@@ -442,12 +443,6 @@ interface PonchoConfig extends McpConfig {
442
443
  url: string;
443
444
  headers?: Record<string, string>;
444
445
  };
445
- latitude?: {
446
- apiKeyEnv?: string;
447
- projectIdEnv?: string;
448
- path?: string;
449
- documentPath?: string;
450
- };
451
446
  handler?: (event: unknown) => Promise<void> | void;
452
447
  };
453
448
  skills?: Record<string, Record<string, unknown>>;
@@ -728,11 +723,9 @@ declare class AgentHarness {
728
723
  private lastSkillRefreshAt;
729
724
  private readonly activeSkillNames;
730
725
  private readonly registeredMcpToolNames;
731
- private latitudeTelemetry?;
732
726
  private otlpSpanProcessor?;
733
727
  private otlpTracerProvider?;
734
728
  private hasOtlpExporter;
735
- private insideTelemetryCapture;
736
729
  private _browserSession?;
737
730
  private _browserMod?;
738
731
  private parsedAgent?;
@@ -801,9 +794,8 @@ declare class AgentHarness {
801
794
  shutdown(): Promise<void>;
802
795
  listTools(): ToolDefinition[];
803
796
  /**
804
- * Wraps the run() generator with telemetry capture for complete trace coverage.
805
- * Supports Latitude, generic OTLP, or both simultaneously.
806
- * Streams events in real-time using an event queue pattern.
797
+ * Wraps the run() generator with an OTel root span (invoke_agent) so all
798
+ * child spans (LLM calls via AI SDK, tool execution) group under one trace.
807
799
  */
808
800
  runWithTelemetry(input: RunInput): AsyncGenerator<AgentEvent>;
809
801
  compact(messages: Message[], options?: CompactMessagesOptions): Promise<CompactResult>;
@@ -824,30 +816,6 @@ declare class AgentHarness {
824
816
  runToCompletion(input: RunInput): Promise<HarnessRunOutput>;
825
817
  }
826
818
 
827
- interface LatitudeCaptureConfig {
828
- apiKeyEnv?: string;
829
- projectIdEnv?: string;
830
- path?: string;
831
- defaultPath?: string;
832
- }
833
- /**
834
- * Reads and validates Latitude telemetry configuration from environment
835
- * variables. The actual telemetry capture is handled by LatitudeTelemetry
836
- * from @latitude-data/telemetry in harness.ts (via runWithTelemetry).
837
- */
838
- declare class LatitudeCapture {
839
- private readonly apiKey?;
840
- private readonly projectId?;
841
- private readonly path?;
842
- constructor(config?: LatitudeCaptureConfig);
843
- isConfigured(): boolean;
844
- getConfig(): {
845
- apiKey: string | undefined;
846
- projectId: number | undefined;
847
- path: string | undefined;
848
- };
849
- }
850
-
851
819
  /**
852
820
  * Converts a JSON Schema object to a Zod schema
853
821
  *
@@ -931,12 +899,6 @@ declare function normalizeOtlp(opt: OtlpOption | undefined): OtlpConfig | undefi
931
899
  interface TelemetryConfig {
932
900
  enabled?: boolean;
933
901
  otlp?: OtlpOption;
934
- latitude?: {
935
- apiKeyEnv?: string;
936
- projectIdEnv?: string;
937
- path?: string;
938
- documentPath?: string;
939
- };
940
902
  handler?: (event: AgentEvent) => Promise<void> | void;
941
903
  }
942
904
  declare class TelemetryEmitter {
@@ -948,4 +910,4 @@ declare class TelemetryEmitter {
948
910
 
949
911
  declare const createSubagentTools: (manager: SubagentManager) => ToolDefinition[];
950
912
 
951
- export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryStateStore, LatitudeCapture, type LatitudeCaptureConfig, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, type ProviderConfig, type Reminder, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SkillContextEntry, type SkillMetadata, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VercelBlobUploadStore, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, createConversationStore, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryTools, createModelProvider, createReminderStore, createReminderTools, createSearchTools, createSkillTools, createStateStore, createSubagentTools, createUploadStore, createWriteTool, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, findSafeSplitPoint, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPonchoStoreRoot, jsonSchemaToZod, loadPonchoConfig, loadSkillContext, loadSkillInstructions, loadSkillMetadata, normalizeOtlp, normalizeScriptPolicyPath, parseAgentFile, parseAgentMarkdown, ponchoDocsTool, readOpenAICodexSession, readSkillResource, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveMemoryConfig, resolveSkillDirs, resolveStateConfig, slugifyStorageComponent, startOpenAICodexDeviceAuth, writeOpenAICodexSession };
913
+ export { type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, type ArchivedToolResult$1 as ArchivedToolResult, type BuiltInToolToggles, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type Conversation, type ConversationState, type ConversationStore, type ConversationSummary, type CronJobConfig, type HarnessOptions, type HarnessRunOutput, InMemoryConversationStore, InMemoryStateStore, LocalMcpBridge, LocalUploadStore, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentResult, type PonchoConfig, type ProviderConfig, type Reminder, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RuntimeRenderContext, S3UploadStore, STORAGE_SCHEMA_VERSION, type SkillContextEntry, type SkillMetadata, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type SubagentManager, type SubagentResult, type SubagentSpawnResult, type SubagentSummary, type TelemetryConfig, TelemetryEmitter, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type UploadStore, type UploadsConfig, VercelBlobUploadStore, buildAgentDirectoryName, buildSkillContextWindow, compactMessages, completeOpenAICodexDeviceAuth, createConversationStore, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryTools, createModelProvider, createReminderStore, createReminderTools, createSearchTools, createSkillTools, createStateStore, createSubagentTools, createUploadStore, createWriteTool, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, findSafeSplitPoint, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPonchoStoreRoot, jsonSchemaToZod, loadPonchoConfig, loadSkillContext, loadSkillInstructions, loadSkillMetadata, normalizeOtlp, normalizeScriptPolicyPath, parseAgentFile, parseAgentMarkdown, ponchoDocsTool, readOpenAICodexSession, readSkillResource, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveMemoryConfig, resolveSkillDirs, resolveStateConfig, slugifyStorageComponent, startOpenAICodexDeviceAuth, writeOpenAICodexSession };
package/dist/index.js CHANGED
@@ -113,11 +113,13 @@ var parseCronJobs = (value) => {
113
113
  validateTimezone(timezone, path);
114
114
  }
115
115
  const channel = typeof jobValue.channel === "string" && jobValue.channel.trim() ? jobValue.channel.trim() : void 0;
116
+ const maxRuns = typeof jobValue.maxRuns === "number" && jobValue.maxRuns > 0 ? Math.max(1, Math.floor(jobValue.maxRuns)) : void 0;
116
117
  jobs[jobName] = {
117
118
  schedule: jobValue.schedule.trim(),
118
119
  task: jobValue.task,
119
120
  timezone,
120
- channel
121
+ channel,
122
+ maxRuns
121
123
  };
122
124
  }
123
125
  return jobs;
@@ -1467,8 +1469,6 @@ All credentials in \`poncho.config.js\` use **env var name** fields (\`*Env\` su
1467
1469
  | \`auth.tokenEnv\` | \`PONCHO_AUTH_TOKEN\` | Auth passphrase / bearer token |
1468
1470
  | \`storage.urlEnv\` | \`UPSTASH_REDIS_REST_URL\` / \`REDIS_URL\` | Storage connection URL |
1469
1471
  | \`storage.tokenEnv\` | \`UPSTASH_REDIS_REST_TOKEN\` | Upstash REST token |
1470
- | \`telemetry.latitude.apiKeyEnv\` | \`LATITUDE_API_KEY\` | Latitude API key |
1471
- | \`telemetry.latitude.projectIdEnv\` | \`LATITUDE_PROJECT_ID\` | Latitude project ID |
1472
1472
  | \`messaging[].botTokenEnv\` | \`SLACK_BOT_TOKEN\` | Slack bot token |
1473
1473
  | \`messaging[].signingSecretEnv\` | \`SLACK_SIGNING_SECRET\` | Slack signing secret |
1474
1474
  | \`messaging[].botTokenEnv\` | \`TELEGRAM_BOT_TOKEN\` | Telegram bot token |
@@ -1557,7 +1557,7 @@ export default {
1557
1557
  },
1558
1558
  },
1559
1559
 
1560
- // Telemetry destination \u2014 generic OTLP and/or Latitude
1560
+ // Telemetry \u2014 send OpenTelemetry traces to any OTLP-compatible collector
1561
1561
  telemetry: {
1562
1562
  enabled: true,
1563
1563
  // Generic OTLP: string shorthand or { url, headers? } object
@@ -1567,12 +1567,6 @@ export default {
1567
1567
  // url: 'https://api.honeycomb.io/v1/traces',
1568
1568
  // headers: { 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY },
1569
1569
  // },
1570
- // Latitude (reads from LATITUDE_API_KEY and LATITUDE_PROJECT_ID env vars by default)
1571
- latitude: {
1572
- // apiKeyEnv: 'LATITUDE_API_KEY', // default
1573
- // projectIdEnv: 'LATITUDE_PROJECT_ID', // default
1574
- path: 'your/prompt-path', // optional, defaults to agent name
1575
- },
1576
1570
  },
1577
1571
 
1578
1572
  // Messaging platform integrations
@@ -1652,9 +1646,6 @@ Remote storage keys are namespaced and versioned, for example \`poncho:v1:<agent
1652
1646
  | \`PONCHO_INTERNAL_SECRET\` | No | Shared secret used by internal serverless callbacks (recommended for Vercel/Lambda) |
1653
1647
  | \`PONCHO_SELF_BASE_URL\` | No | Explicit base URL for internal self-callbacks when auto-detection is unavailable |
1654
1648
  | \`OTEL_EXPORTER_OTLP_ENDPOINT\` | No | OTLP trace endpoint (Jaeger, Tempo, Honeycomb, etc.) |
1655
- | \`LATITUDE_API_KEY\` | No | Latitude dashboard integration |
1656
- | \`LATITUDE_PROJECT_ID\` | No | Latitude project identifier for capture traces |
1657
- | \`LATITUDE_PATH\` | No | Latitude prompt path for grouping traces |
1658
1649
  | \`KV_REST_API_URL\` | No | Upstash REST URL (Vercel Marketplace naming) |
1659
1650
  | \`KV_REST_API_TOKEN\` | No | Upstash REST write token (Vercel Marketplace naming) |
1660
1651
  | \`UPSTASH_REDIS_REST_URL\` | No | Upstash REST URL (direct Upstash naming) |
@@ -1732,30 +1723,6 @@ export default {
1732
1723
  }
1733
1724
  \`\`\`
1734
1725
 
1735
- ### Latitude integration (optional)
1736
-
1737
- Send traces to [Latitude](https://latitude.so) for a dashboard with cost tracking and prompt management:
1738
-
1739
- \`\`\`bash
1740
- LATITUDE_API_KEY=lat_xxx
1741
- LATITUDE_PROJECT_ID=123
1742
- LATITUDE_PATH=agents/my-agent/run
1743
- \`\`\`
1744
-
1745
- Or configure via \`poncho.config.js\`:
1746
-
1747
- \`\`\`javascript
1748
- telemetry: {
1749
- latitude: {
1750
- // apiKeyEnv: 'LATITUDE_API_KEY', // default
1751
- // projectIdEnv: 'LATITUDE_PROJECT_ID', // default
1752
- path: 'your/prompt-path',
1753
- },
1754
- }
1755
- \`\`\`
1756
-
1757
- Both \`otlp\` and \`latitude\` can be configured simultaneously \u2014 all spans flow to both destinations.
1758
-
1759
1726
  ## Security
1760
1727
 
1761
1728
  ### Protect your endpoint
@@ -5376,8 +5343,7 @@ var createSubagentTools = (manager) => [
5376
5343
  ];
5377
5344
 
5378
5345
  // src/harness.ts
5379
- import { LatitudeTelemetry } from "@latitude-data/telemetry";
5380
- import { trace, context as otelContext, SpanStatusCode } from "@opentelemetry/api";
5346
+ import { trace, context as otelContext, SpanStatusCode, SpanKind } from "@opentelemetry/api";
5381
5347
  import { NodeTracerProvider, BatchSpanProcessor } from "@opentelemetry/sdk-trace-node";
5382
5348
  import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
5383
5349
 
@@ -5910,25 +5876,17 @@ When modifying \`AGENT.md\`, follow these rules strictly:
5910
5876
 
5911
5877
  ## Telemetry Configuration (\`poncho.config.js\`)
5912
5878
 
5913
- When configuring Latitude telemetry, use **exactly** these field names:
5879
+ Send OpenTelemetry traces to any OTLP-compatible collector (Jaeger, Grafana Tempo, Honeycomb, Datadog, etc.):
5914
5880
 
5915
5881
  \`\`\`javascript
5916
5882
  telemetry: {
5917
5883
  enabled: true,
5918
- latitude: {
5919
- apiKeyEnv: "LATITUDE_API_KEY", // env var name (default)
5920
- projectIdEnv: "LATITUDE_PROJECT_ID", // env var name (default)
5921
- path: "your/prompt-path", // optional, defaults to agent name
5922
- },
5884
+ otlp: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
5885
+ // Or with auth headers:
5886
+ // otlp: { url: "https://api.honeycomb.io/v1/traces", headers: { "x-honeycomb-team": process.env.HONEYCOMB_API_KEY } },
5923
5887
  },
5924
5888
  \`\`\`
5925
5889
 
5926
- - \`apiKeyEnv\` specifies the environment variable name for the Latitude API key (defaults to \`"LATITUDE_API_KEY"\`).
5927
- - \`projectIdEnv\` specifies the environment variable name for the project ID (defaults to \`"LATITUDE_PROJECT_ID"\`).
5928
- - With defaults, you only need \`telemetry: { latitude: {} }\` if the env vars are already named \`LATITUDE_API_KEY\` and \`LATITUDE_PROJECT_ID\`.
5929
- - \`path\` must only contain letters, numbers, hyphens, underscores, dots, and slashes.
5930
- - For a generic OTLP endpoint instead: \`telemetry: { otlp: process.env.OTEL_EXPORTER_OTLP_ENDPOINT }\`.
5931
-
5932
5890
  ## Credential Configuration Pattern
5933
5891
 
5934
5892
  All credentials in \`poncho.config.js\` use the **env var name** pattern (\`*Env\` fields). Config specifies which environment variable to read \u2014 never the secret itself. Sensible defaults mean zero config when using conventional env var names.
@@ -5953,10 +5911,7 @@ export default {
5953
5911
  tokenEnv: "UPSTASH_REDIS_REST_TOKEN", // default (falls back to KV_REST_API_TOKEN)
5954
5912
  },
5955
5913
  telemetry: {
5956
- latitude: {
5957
- apiKeyEnv: "LATITUDE_API_KEY", // default
5958
- projectIdEnv: "LATITUDE_PROJECT_ID", // default
5959
- },
5914
+ otlp: process.env.OTEL_EXPORTER_OTLP_ENDPOINT,
5960
5915
  },
5961
5916
  messaging: [{ platform: "slack" }], // reads SLACK_BOT_TOKEN, SLACK_SIGNING_SECRET by default
5962
5917
  }
@@ -6035,11 +5990,9 @@ var AgentHarness = class _AgentHarness {
6035
5990
  lastSkillRefreshAt = 0;
6036
5991
  activeSkillNames = /* @__PURE__ */ new Set();
6037
5992
  registeredMcpToolNames = /* @__PURE__ */ new Set();
6038
- latitudeTelemetry;
6039
5993
  otlpSpanProcessor;
6040
5994
  otlpTracerProvider;
6041
5995
  hasOtlpExporter = false;
6042
- insideTelemetryCapture = false;
6043
5996
  _browserSession;
6044
5997
  _browserMod;
6045
5998
  parsedAgent;
@@ -6648,22 +6601,6 @@ var AgentHarness = class _AgentHarness {
6648
6601
  await bridge.discoverTools();
6649
6602
  await this.refreshMcpTools("initialize");
6650
6603
  const telemetryEnabled = config?.telemetry?.enabled !== false;
6651
- const latitudeBlock = config?.telemetry?.latitude;
6652
- const latApiKeyEnv = latitudeBlock?.apiKeyEnv ?? "LATITUDE_API_KEY";
6653
- const latProjectIdEnv = latitudeBlock?.projectIdEnv ?? "LATITUDE_PROJECT_ID";
6654
- const latitudeApiKey = process.env[latApiKeyEnv];
6655
- const rawProjectId = process.env[latProjectIdEnv];
6656
- const latitudeProjectId = rawProjectId ? parseInt(rawProjectId, 10) : void 0;
6657
- if (telemetryEnabled && latitudeApiKey && latitudeProjectId) {
6658
- this.latitudeTelemetry = new LatitudeTelemetry(latitudeApiKey);
6659
- } else if (telemetryEnabled && latitudeBlock && (!latitudeApiKey || !latitudeProjectId)) {
6660
- const missing = [];
6661
- if (!latitudeApiKey) missing.push(`${latApiKeyEnv} env var`);
6662
- if (!latitudeProjectId) missing.push(`${latProjectIdEnv} env var`);
6663
- console.warn(
6664
- `[poncho][telemetry] Latitude telemetry is configured but missing: ${missing.join(", ")}. Traces will NOT be sent.`
6665
- );
6666
- }
6667
6604
  const otlpConfig = telemetryEnabled ? normalizeOtlp(config?.telemetry?.otlp) : void 0;
6668
6605
  if (otlpConfig) {
6669
6606
  const exporter = new OTLPTraceExporter({
@@ -6672,22 +6609,13 @@ var AgentHarness = class _AgentHarness {
6672
6609
  });
6673
6610
  const processor = new BatchSpanProcessor(exporter);
6674
6611
  this.otlpSpanProcessor = processor;
6675
- if (this.latitudeTelemetry) {
6676
- const globalProvider = trace.getTracerProvider();
6677
- const delegate = globalProvider.getDelegate?.() ?? globalProvider;
6678
- if (typeof delegate.addSpanProcessor === "function") {
6679
- delegate.addSpanProcessor(processor);
6680
- }
6681
- console.info(`[poncho][telemetry] OTLP exporter added (piggybacking on Latitude provider) \u2192 ${otlpConfig.url}`);
6682
- } else {
6683
- const provider2 = new NodeTracerProvider({
6684
- spanProcessors: [processor]
6685
- });
6686
- provider2.register();
6687
- this.otlpTracerProvider = provider2;
6688
- console.info(`[poncho][telemetry] OTLP exporter active (standalone provider) \u2192 ${otlpConfig.url}`);
6689
- }
6612
+ const provider2 = new NodeTracerProvider({
6613
+ spanProcessors: [processor]
6614
+ });
6615
+ provider2.register();
6616
+ this.otlpTracerProvider = provider2;
6690
6617
  this.hasOtlpExporter = true;
6618
+ console.info(`[poncho][telemetry] OTLP exporter active \u2192 ${otlpConfig.url}`);
6691
6619
  }
6692
6620
  }
6693
6621
  async buildBrowserStoragePersistence(config, sessionId) {
@@ -6831,14 +6759,6 @@ var AgentHarness = class _AgentHarness {
6831
6759
  this._browserSession = void 0;
6832
6760
  }
6833
6761
  await this.mcpBridge?.stopLocalServers();
6834
- if (this.latitudeTelemetry) {
6835
- await this.latitudeTelemetry.shutdown().catch((err) => {
6836
- console.warn(
6837
- `[poncho][telemetry] Latitude telemetry shutdown error: ${err instanceof Error ? err.message : String(err)}`
6838
- );
6839
- });
6840
- this.latitudeTelemetry = void 0;
6841
- }
6842
6762
  if (this.otlpSpanProcessor) {
6843
6763
  await this.otlpSpanProcessor.shutdown().catch((err) => {
6844
6764
  console.warn(
@@ -6861,85 +6781,21 @@ var AgentHarness = class _AgentHarness {
6861
6781
  return this.dispatcher.list();
6862
6782
  }
6863
6783
  /**
6864
- * Wraps the run() generator with telemetry capture for complete trace coverage.
6865
- * Supports Latitude, generic OTLP, or both simultaneously.
6866
- * Streams events in real-time using an event queue pattern.
6784
+ * Wraps the run() generator with an OTel root span (invoke_agent) so all
6785
+ * child spans (LLM calls via AI SDK, tool execution) group under one trace.
6867
6786
  */
6868
6787
  async *runWithTelemetry(input) {
6869
- const config = this.loadedConfig;
6870
- const telemetry = this.latitudeTelemetry;
6871
- if (telemetry) {
6872
- const latProjectIdEnv2 = config?.telemetry?.latitude?.projectIdEnv ?? "LATITUDE_PROJECT_ID";
6873
- const projectId = parseInt(process.env[latProjectIdEnv2] ?? "", 10);
6874
- const rawPath = config?.telemetry?.latitude?.path ?? this.parsedAgent?.frontmatter.name ?? "agent";
6875
- const path = rawPath.replace(/[^\w\-./]/g, "-").replace(/-+/g, "-").replace(/^-+|-+$/g, "") || "agent";
6876
- const rawConversationId = input.conversationId ?? (typeof input.parameters?.__activeConversationId === "string" ? input.parameters.__activeConversationId : void 0);
6877
- const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
6878
- const conversationUuid = rawConversationId && UUID_RE.test(rawConversationId) ? rawConversationId : void 0;
6879
- console.info(
6880
- `[poncho][telemetry] Latitude telemetry active \u2013 projectId=${projectId}, path="${path}"${conversationUuid ? `, conversation="${conversationUuid}"` : ""}`
6881
- );
6882
- const eventQueue = [];
6883
- let queueResolve = null;
6884
- let generatorDone = false;
6885
- let generatorError = null;
6886
- const capturePromise = telemetry.capture({ projectId, path, conversationUuid }, async () => {
6887
- this.insideTelemetryCapture = true;
6888
- try {
6889
- for await (const event of this.run(input)) {
6890
- eventQueue.push(event);
6891
- if (queueResolve) {
6892
- const resolve14 = queueResolve;
6893
- queueResolve = null;
6894
- resolve14();
6895
- }
6896
- }
6897
- } catch (error) {
6898
- generatorError = error;
6899
- } finally {
6900
- this.insideTelemetryCapture = false;
6901
- generatorDone = true;
6902
- if (queueResolve) {
6903
- queueResolve();
6904
- queueResolve = null;
6905
- }
6788
+ if (this.hasOtlpExporter) {
6789
+ const tracer = trace.getTracer("gen_ai");
6790
+ const agentName = this.parsedAgent?.frontmatter.name ?? "agent";
6791
+ const rootSpan = tracer.startSpan(`invoke_agent ${agentName}`, {
6792
+ kind: SpanKind.INTERNAL,
6793
+ attributes: {
6794
+ "gen_ai.operation.name": "invoke_agent",
6795
+ ...input.conversationId ? { "gen_ai.conversation.id": input.conversationId } : {}
6906
6796
  }
6907
6797
  });
6908
- try {
6909
- while (!generatorDone || eventQueue.length > 0) {
6910
- if (eventQueue.length > 0) {
6911
- yield eventQueue.shift();
6912
- } else if (!generatorDone) {
6913
- await new Promise((resolve14) => {
6914
- queueResolve = resolve14;
6915
- });
6916
- }
6917
- }
6918
- if (generatorError) {
6919
- throw generatorError;
6920
- }
6921
- } finally {
6922
- try {
6923
- await capturePromise;
6924
- } finally {
6925
- try {
6926
- await telemetry.flush();
6927
- console.info("[poncho][telemetry] flush completed");
6928
- } catch (flushErr) {
6929
- console.error("[poncho][telemetry] flush failed:", flushErr);
6930
- }
6931
- }
6932
- }
6933
- } else if (this.hasOtlpExporter) {
6934
- const tracer = trace.getTracer("poncho");
6935
- const agentName = this.parsedAgent?.frontmatter.name ?? "agent";
6936
- const rootSpan = tracer.startSpan(`agent.run ${agentName}`);
6937
- rootSpan.setAttribute("poncho.agent.name", agentName);
6938
- if (input.conversationId) {
6939
- rootSpan.setAttribute("poncho.conversation.id", input.conversationId);
6940
- }
6941
6798
  const spanContext = trace.setSpan(otelContext.active(), rootSpan);
6942
- this.insideTelemetryCapture = true;
6943
6799
  try {
6944
6800
  const gen = this.run(input);
6945
6801
  let next;
@@ -6956,7 +6812,6 @@ var AgentHarness = class _AgentHarness {
6956
6812
  rootSpan.recordException(error instanceof Error ? error : new Error(String(error)));
6957
6813
  throw error;
6958
6814
  } finally {
6959
- this.insideTelemetryCapture = false;
6960
6815
  rootSpan.end();
6961
6816
  try {
6962
6817
  await this.otlpSpanProcessor?.forceFlush();
@@ -6982,6 +6837,7 @@ var AgentHarness = class _AgentHarness {
6982
6837
  await this.initialize();
6983
6838
  }
6984
6839
  const memoryPromise = this.memoryStore ? this.memoryStore.getMainMemory() : void 0;
6840
+ const todosPromise = this.todoStore ? this.todoStore.get(input.conversationId ?? "__default__") : void 0;
6985
6841
  await this.refreshAgentIfChanged();
6986
6842
  await this.refreshSkillsIfChanged();
6987
6843
  let agent = this.parsedAgent;
@@ -7053,6 +6909,14 @@ Each conversation gets its own browser tab sharing a single browser instance. Ca
7053
6909
  ## Persistent Memory
7054
6910
 
7055
6911
  ${boundedMainMemory.trim()}` : "";
6912
+ const openTodos = (await todosPromise)?.filter(
6913
+ (t) => t.status === "pending" || t.status === "in_progress"
6914
+ ) ?? [];
6915
+ const todoContext = openTodos.length > 0 ? `
6916
+
6917
+ ## Open Tasks
6918
+
6919
+ ${openTodos.map((t) => `- [${t.status === "in_progress" ? "IN PROGRESS" : "PENDING"}] ${t.content} (id: ${t.id})`).join("\n")}` : "";
7056
6920
  const buildSystemPrompt = () => {
7057
6921
  const agentPrompt = renderCurrentAgentPrompt();
7058
6922
  const promptWithSkills = this.skillContextWindow ? `${agentPrompt}${developmentContext}
@@ -7061,16 +6925,9 @@ ${this.skillContextWindow}${browserContext}` : `${agentPrompt}${developmentConte
7061
6925
  const timeContext = this.reminderStore ? `
7062
6926
 
7063
6927
  Current UTC time: ${(/* @__PURE__ */ new Date()).toISOString()}` : "";
7064
- return `${promptWithSkills}${memoryContext}${timeContext}
7065
-
7066
- ## Execution Integrity
7067
-
7068
- - Do not claim that you executed a tool unless you actually emitted a tool call in this run.
7069
- - Do not fabricate "Tool Used" or "Tool Result" logs as plain text.
7070
- - Never output faux execution transcripts, markdown tool logs, or "Tool Used/Result" sections.
7071
- - If no suitable tool is available, explicitly say that and ask for guidance.`;
6928
+ return `${promptWithSkills}${memoryContext}${todoContext}${timeContext}`;
7072
6929
  };
7073
- let integrityPrompt = buildSystemPrompt();
6930
+ let systemPrompt = buildSystemPrompt();
7074
6931
  let lastPromptFingerprint = `${this.agentFileFingerprint}
7075
6932
  ${this.skillFingerprint}`;
7076
6933
  const pushEvent = (event) => {
@@ -7232,7 +7089,7 @@ ${this.skillFingerprint}`;
7232
7089
  inputSchema: t.inputSchema
7233
7090
  }))
7234
7091
  );
7235
- const requestTokenEstimate = estimateTotalTokens(integrityPrompt, messages, toolDefsJsonForEstimate);
7092
+ const requestTokenEstimate = estimateTotalTokens(systemPrompt, messages, toolDefsJsonForEstimate);
7236
7093
  yield pushEvent({ type: "model:request", tokens: requestTokenEstimate });
7237
7094
  const convertMessage = async (msg) => {
7238
7095
  if (msg.role === "tool") {
@@ -7424,7 +7281,7 @@ ${textContent}` };
7424
7281
  const modelInstance = this.modelProvider(modelName);
7425
7282
  const compactionConfig = resolveCompactionConfig(agent.frontmatter.compaction);
7426
7283
  if (compactionConfig.enabled && (step === 1 || step % COMPACTION_CHECK_INTERVAL_STEPS === 0)) {
7427
- const estimated = estimateTotalTokens(integrityPrompt, messages, toolDefsJsonForEstimate);
7284
+ const estimated = estimateTotalTokens(systemPrompt, messages, toolDefsJsonForEstimate);
7428
7285
  const lastReportedInput = totalInputTokens > 0 ? totalInputTokens : 0;
7429
7286
  const effectiveTokens = Math.max(estimated, lastReportedInput);
7430
7287
  if (effectiveTokens > compactionConfig.trigger * contextWindow) {
@@ -7444,7 +7301,7 @@ ${textContent}` };
7444
7301
  emittedMessages.pop();
7445
7302
  }
7446
7303
  }
7447
- const tokensAfterCompaction = estimateTotalTokens(integrityPrompt, messages, toolDefsJsonForEstimate);
7304
+ const tokensAfterCompaction = estimateTotalTokens(systemPrompt, messages, toolDefsJsonForEstimate);
7448
7305
  latestContextTokens = tokensAfterCompaction;
7449
7306
  toolOutputEstimateSinceModel = 0;
7450
7307
  yield pushEvent({
@@ -7475,14 +7332,14 @@ ${textContent}` };
7475
7332
  const telemetryEnabled = this.loadedConfig?.telemetry?.enabled !== false;
7476
7333
  const result = await streamText({
7477
7334
  model: modelInstance,
7478
- system: integrityPrompt,
7335
+ system: systemPrompt,
7479
7336
  messages: cachedMessages,
7480
7337
  tools,
7481
7338
  temperature,
7482
7339
  abortSignal: input.abortSignal,
7483
7340
  ...typeof maxTokens === "number" ? { maxTokens } : {},
7484
7341
  experimental_telemetry: {
7485
- isEnabled: telemetryEnabled && !!(this.latitudeTelemetry || this.hasOtlpExporter),
7342
+ isEnabled: telemetryEnabled && this.hasOtlpExporter,
7486
7343
  recordInputs: true,
7487
7344
  recordOutputs: true
7488
7345
  }
@@ -7827,36 +7684,21 @@ ${textContent}` };
7827
7684
  return;
7828
7685
  }
7829
7686
  const toolSpans = /* @__PURE__ */ new Map();
7830
- if (this.insideTelemetryCapture && this.latitudeTelemetry) {
7831
- for (const call of approvedCalls) {
7832
- toolSpans.set(
7833
- call.id,
7834
- this.latitudeTelemetry.span.tool({
7835
- name: call.name,
7836
- call: { id: call.id, arguments: call.input }
7837
- })
7838
- );
7839
- }
7840
- } else if (this.insideTelemetryCapture && this.hasOtlpExporter) {
7841
- const tracer = trace.getTracer("poncho");
7687
+ if (this.hasOtlpExporter) {
7688
+ const tracer = trace.getTracer("gen_ai");
7842
7689
  for (const call of approvedCalls) {
7843
- const span = tracer.startSpan(`tool ${call.name}`, {
7690
+ const toolDef = this.dispatcher.get(call.name);
7691
+ toolSpans.set(call.id, tracer.startSpan(`execute_tool ${call.name}`, {
7692
+ kind: SpanKind.INTERNAL,
7844
7693
  attributes: {
7845
- "poncho.tool.name": call.name,
7846
- "poncho.tool.call_id": call.id,
7847
- "poncho.tool.arguments": JSON.stringify(call.input)
7848
- }
7849
- });
7850
- toolSpans.set(call.id, {
7851
- end(opts) {
7852
- if (opts.result.isError) {
7853
- span.setStatus({ code: SpanStatusCode.ERROR, message: String(opts.result.value) });
7854
- } else {
7855
- span.setStatus({ code: SpanStatusCode.OK });
7856
- }
7857
- span.end();
7694
+ "gen_ai.operation.name": "execute_tool",
7695
+ "gen_ai.tool.name": call.name,
7696
+ "gen_ai.tool.call.id": call.id,
7697
+ "gen_ai.tool.type": "function",
7698
+ ...toolDef?.description ? { "gen_ai.tool.description": toolDef.description } : {},
7699
+ "gen_ai.tool.call.arguments": JSON.stringify(call.input)
7858
7700
  }
7859
- });
7701
+ }));
7860
7702
  }
7861
7703
  }
7862
7704
  const TOOL_DEADLINE_SENTINEL = /* @__PURE__ */ Symbol("tool_deadline");
@@ -7916,7 +7758,12 @@ ${textContent}` };
7916
7758
  for (const result2 of batchResults) {
7917
7759
  const span = toolSpans.get(result2.callId);
7918
7760
  if (result2.error) {
7919
- span?.end({ result: { value: result2.error, isError: true } });
7761
+ if (span) {
7762
+ span.setAttribute("error.type", "Error");
7763
+ span.setStatus({ code: SpanStatusCode.ERROR, message: result2.error });
7764
+ span.recordException(new Error(result2.error));
7765
+ span.end();
7766
+ }
7920
7767
  yield pushEvent({
7921
7768
  type: "tool:error",
7922
7769
  tool: result2.tool,
@@ -7950,7 +7797,11 @@ ${textContent}` };
7950
7797
  output: { type: "json", value: { error: result2.error } }
7951
7798
  });
7952
7799
  } else {
7953
- span?.end({ result: { value: result2.output ?? null, isError: false } });
7800
+ if (span) {
7801
+ span.setAttribute("gen_ai.tool.call.result", JSON.stringify(result2.output ?? null));
7802
+ span.setStatus({ code: SpanStatusCode.OK });
7803
+ span.end();
7804
+ }
7954
7805
  const serialized = JSON.stringify(result2.output ?? null);
7955
7806
  const outputTokenEstimate = Math.ceil(serialized.length / 4);
7956
7807
  toolOutputEstimateSinceModel += outputTokenEstimate;
@@ -8060,7 +7911,7 @@ ${textContent}` };
8060
7911
  const currentFingerprint = `${this.agentFileFingerprint}
8061
7912
  ${this.skillFingerprint}`;
8062
7913
  if (currentFingerprint !== lastPromptFingerprint) {
8063
- integrityPrompt = buildSystemPrompt();
7914
+ systemPrompt = buildSystemPrompt();
8064
7915
  lastPromptFingerprint = currentFingerprint;
8065
7916
  }
8066
7917
  }
@@ -8232,33 +8083,6 @@ ${this.skillFingerprint}`;
8232
8083
  }
8233
8084
  };
8234
8085
 
8235
- // src/latitude-capture.ts
8236
- var LatitudeCapture = class {
8237
- apiKey;
8238
- projectId;
8239
- path;
8240
- constructor(config) {
8241
- const apiKeyEnv = config?.apiKeyEnv ?? "LATITUDE_API_KEY";
8242
- this.apiKey = process.env[apiKeyEnv];
8243
- const projectIdEnv = config?.projectIdEnv ?? "LATITUDE_PROJECT_ID";
8244
- const rawProjectId = process.env[projectIdEnv];
8245
- const projectIdNumber = rawProjectId ? Number.parseInt(rawProjectId, 10) : Number.NaN;
8246
- this.projectId = Number.isFinite(projectIdNumber) ? projectIdNumber : void 0;
8247
- const rawPath = config?.path ?? process.env.LATITUDE_PATH ?? process.env.LATITUDE_DOCUMENT_PATH ?? config?.defaultPath;
8248
- this.path = rawPath;
8249
- }
8250
- isConfigured() {
8251
- return !!(this.apiKey && this.projectId && this.path);
8252
- }
8253
- getConfig() {
8254
- return {
8255
- apiKey: this.apiKey,
8256
- projectId: this.projectId,
8257
- path: this.path
8258
- };
8259
- }
8260
- };
8261
-
8262
8086
  // src/state.ts
8263
8087
  import { randomUUID as randomUUID4 } from "crypto";
8264
8088
  import { mkdir as mkdir7, readFile as readFile11, readdir as readdir4, rename as rename4, rm as rm4, writeFile as writeFile8 } from "fs/promises";
@@ -9432,7 +9256,6 @@ export {
9432
9256
  AgentHarness,
9433
9257
  InMemoryConversationStore,
9434
9258
  InMemoryStateStore,
9435
- LatitudeCapture,
9436
9259
  LocalMcpBridge,
9437
9260
  LocalUploadStore,
9438
9261
  OPENAI_CODEX_CLIENT_ID,