@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.
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +6 -0
- package/dist/index.d.ts +4 -42
- package/dist/index.js +66 -243
- package/package.json +1 -2
- package/src/agent-parser.ts +7 -0
- package/src/config.ts +0 -6
- package/src/harness.ts +69 -215
- package/src/index.ts +0 -1
- package/src/telemetry.ts +0 -8
- package/test/agent-parser.test.ts +74 -0
- package/test/telemetry.test.ts +0 -21
- package/.turbo/turbo-lint.log +0 -6
- package/.turbo/turbo-test.log +0 -34
- package/src/latitude-capture.ts +0 -48
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.
|
|
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
|
[34mCLI[39m tsup v8.5.1
|
|
9
9
|
[34mCLI[39m Target: es2022
|
|
10
10
|
[34mESM[39m Build start
|
|
11
|
-
[32mESM[39m [1mdist/index.js [22m[
|
|
12
|
-
[32mESM[39m ⚡️ Build success in
|
|
11
|
+
[32mESM[39m [1mdist/index.js [22m[32m334.17 KB[39m
|
|
12
|
+
[32mESM[39m ⚡️ Build success in 152ms
|
|
13
13
|
[34mDTS[39m Build start
|
|
14
|
-
[32mDTS[39m ⚡️ Build success in
|
|
15
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[
|
|
14
|
+
[32mDTS[39m ⚡️ Build success in 7104ms
|
|
15
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m33.55 KB[39m
|
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
|
|
805
|
-
*
|
|
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,
|
|
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
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
5919
|
-
|
|
5920
|
-
|
|
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
|
-
|
|
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
|
-
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
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
|
|
6865
|
-
*
|
|
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
|
-
|
|
6870
|
-
|
|
6871
|
-
|
|
6872
|
-
const
|
|
6873
|
-
|
|
6874
|
-
|
|
6875
|
-
|
|
6876
|
-
|
|
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
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
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 &&
|
|
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.
|
|
7831
|
-
|
|
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
|
|
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
|
-
"
|
|
7846
|
-
"
|
|
7847
|
-
"
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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,
|