@poncho-ai/harness 0.5.0 → 0.6.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 +12 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +66 -1
- package/package.json +1 -1
- package/src/harness.ts +83 -8
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.
|
|
2
|
+
> @poncho-ai/harness@0.6.0 build /Users/cesar/Dev/latitude/poncho-ai/packages/harness
|
|
3
3
|
> tsup src/index.ts --format esm --dts
|
|
4
4
|
|
|
5
5
|
CLI Building entry: src/index.ts
|
|
@@ -7,8 +7,8 @@ CLI Using tsconfig: tsconfig.json
|
|
|
7
7
|
CLI tsup v8.5.1
|
|
8
8
|
CLI Target: es2022
|
|
9
9
|
ESM Build start
|
|
10
|
-
ESM dist/index.js
|
|
11
|
-
ESM ⚡️ Build success in
|
|
10
|
+
ESM dist/index.js 114.60 KB
|
|
11
|
+
ESM ⚡️ Build success in 69ms
|
|
12
12
|
DTS Build start
|
|
13
|
-
DTS ⚡️ Build success in
|
|
14
|
-
DTS dist/index.d.ts
|
|
13
|
+
DTS ⚡️ Build success in 2819ms
|
|
14
|
+
DTS dist/index.d.ts 16.10 KB
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# @poncho-ai/harness
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Add markdown table support and fix Latitude telemetry integration
|
|
8
|
+
- Add markdown table rendering with `marked` library in web UI
|
|
9
|
+
- Add table styling with horizontal scroll and hover effects
|
|
10
|
+
- Add margins to HR elements for better spacing
|
|
11
|
+
- Integrate Latitude telemetry with Vercel AI SDK using event queue pattern
|
|
12
|
+
- Enable real-time streaming while capturing complete traces
|
|
13
|
+
- Fix telemetry to show all messages and interactions in Latitude dashboard
|
|
14
|
+
|
|
3
15
|
## 0.5.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -323,6 +323,11 @@ declare class AgentHarness {
|
|
|
323
323
|
initialize(): Promise<void>;
|
|
324
324
|
shutdown(): Promise<void>;
|
|
325
325
|
listTools(): ToolDefinition[];
|
|
326
|
+
/**
|
|
327
|
+
* Wraps the run() generator with Latitude telemetry capture for complete trace coverage
|
|
328
|
+
* Streams events in real-time using an event queue pattern
|
|
329
|
+
*/
|
|
330
|
+
runWithTelemetry(input: RunInput): AsyncGenerator<AgentEvent>;
|
|
326
331
|
run(input: RunInput): AsyncGenerator<AgentEvent>;
|
|
327
332
|
runToCompletion(input: RunInput): Promise<HarnessRunOutput>;
|
|
328
333
|
}
|
package/dist/index.js
CHANGED
|
@@ -1863,6 +1863,9 @@ var extractRunnableFunction = (value) => {
|
|
|
1863
1863
|
return void 0;
|
|
1864
1864
|
};
|
|
1865
1865
|
|
|
1866
|
+
// src/harness.ts
|
|
1867
|
+
import { LatitudeTelemetry } from "@latitude-data/telemetry";
|
|
1868
|
+
|
|
1866
1869
|
// src/tool-dispatcher.ts
|
|
1867
1870
|
var ToolDispatcher = class {
|
|
1868
1871
|
tools = /* @__PURE__ */ new Map();
|
|
@@ -2229,6 +2232,63 @@ var AgentHarness = class {
|
|
|
2229
2232
|
listTools() {
|
|
2230
2233
|
return this.dispatcher.list();
|
|
2231
2234
|
}
|
|
2235
|
+
/**
|
|
2236
|
+
* Wraps the run() generator with Latitude telemetry capture for complete trace coverage
|
|
2237
|
+
* Streams events in real-time using an event queue pattern
|
|
2238
|
+
*/
|
|
2239
|
+
async *runWithTelemetry(input) {
|
|
2240
|
+
const config = this.loadedConfig;
|
|
2241
|
+
const telemetryEnabled = config?.telemetry?.enabled !== false;
|
|
2242
|
+
const latitudeApiKey = config?.telemetry?.latitude?.apiKey;
|
|
2243
|
+
const rawProjectId = config?.telemetry?.latitude?.projectId;
|
|
2244
|
+
const projectId = typeof rawProjectId === "string" ? parseInt(rawProjectId, 10) : rawProjectId;
|
|
2245
|
+
const path = config?.telemetry?.latitude?.path ?? this.parsedAgent?.frontmatter.name ?? "agent";
|
|
2246
|
+
if (telemetryEnabled && latitudeApiKey && projectId) {
|
|
2247
|
+
const telemetry = new LatitudeTelemetry(latitudeApiKey);
|
|
2248
|
+
const eventQueue = [];
|
|
2249
|
+
let queueResolve = null;
|
|
2250
|
+
let generatorDone = false;
|
|
2251
|
+
let generatorError = null;
|
|
2252
|
+
const capturePromise = telemetry.capture({ projectId, path }, async () => {
|
|
2253
|
+
try {
|
|
2254
|
+
for await (const event of this.run(input)) {
|
|
2255
|
+
eventQueue.push(event);
|
|
2256
|
+
if (queueResolve) {
|
|
2257
|
+
const resolve8 = queueResolve;
|
|
2258
|
+
queueResolve = null;
|
|
2259
|
+
resolve8();
|
|
2260
|
+
}
|
|
2261
|
+
}
|
|
2262
|
+
} catch (error) {
|
|
2263
|
+
generatorError = error;
|
|
2264
|
+
} finally {
|
|
2265
|
+
generatorDone = true;
|
|
2266
|
+
if (queueResolve) {
|
|
2267
|
+
queueResolve();
|
|
2268
|
+
queueResolve = null;
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
});
|
|
2272
|
+
try {
|
|
2273
|
+
while (!generatorDone || eventQueue.length > 0) {
|
|
2274
|
+
if (eventQueue.length > 0) {
|
|
2275
|
+
yield eventQueue.shift();
|
|
2276
|
+
} else if (!generatorDone) {
|
|
2277
|
+
await new Promise((resolve8) => {
|
|
2278
|
+
queueResolve = resolve8;
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
}
|
|
2282
|
+
if (generatorError) {
|
|
2283
|
+
throw generatorError;
|
|
2284
|
+
}
|
|
2285
|
+
} finally {
|
|
2286
|
+
await capturePromise;
|
|
2287
|
+
}
|
|
2288
|
+
} else {
|
|
2289
|
+
yield* this.run(input);
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2232
2292
|
async *run(input) {
|
|
2233
2293
|
if (!this.parsedAgent) {
|
|
2234
2294
|
await this.initialize();
|
|
@@ -2374,13 +2434,18 @@ ${boundedMainMemory.trim()}` : "";
|
|
|
2374
2434
|
const modelName = agent.frontmatter.model?.name ?? "claude-opus-4-5";
|
|
2375
2435
|
const temperature = agent.frontmatter.model?.temperature ?? 0.2;
|
|
2376
2436
|
const maxTokens = agent.frontmatter.model?.maxTokens ?? 1024;
|
|
2437
|
+
const telemetryEnabled = this.loadedConfig?.telemetry?.enabled !== false;
|
|
2438
|
+
const latitudeApiKey = this.loadedConfig?.telemetry?.latitude?.apiKey;
|
|
2377
2439
|
const result = await streamText({
|
|
2378
2440
|
model: this.modelProvider(modelName),
|
|
2379
2441
|
system: integrityPrompt,
|
|
2380
2442
|
messages: coreMessages,
|
|
2381
2443
|
tools,
|
|
2382
2444
|
temperature,
|
|
2383
|
-
maxTokens
|
|
2445
|
+
maxTokens,
|
|
2446
|
+
experimental_telemetry: {
|
|
2447
|
+
isEnabled: telemetryEnabled && !!latitudeApiKey
|
|
2448
|
+
}
|
|
2384
2449
|
});
|
|
2385
2450
|
let streamedAnyChunk = false;
|
|
2386
2451
|
let fullText = "";
|
package/package.json
CHANGED
package/src/harness.ts
CHANGED
|
@@ -22,6 +22,7 @@ import { streamText, type CoreMessage } from "ai";
|
|
|
22
22
|
import { jsonSchemaToZod } from "./schema-converter.js";
|
|
23
23
|
import type { SkillMetadata } from "./skill-context.js";
|
|
24
24
|
import { createSkillTools } from "./skill-tools.js";
|
|
25
|
+
import { LatitudeTelemetry } from "@latitude-data/telemetry";
|
|
25
26
|
import {
|
|
26
27
|
applyToolPolicy,
|
|
27
28
|
matchesSlashPattern,
|
|
@@ -355,7 +356,6 @@ export class AgentHarness {
|
|
|
355
356
|
this.registerConfiguredBuiltInTools(config);
|
|
356
357
|
const provider = this.parsedAgent.frontmatter.model?.provider ?? "anthropic";
|
|
357
358
|
const memoryConfig = resolveMemoryConfig(config);
|
|
358
|
-
// TODO: Integrate Latitude telemetry with Vercel AI SDK
|
|
359
359
|
// Only create modelProvider if one wasn't injected (for production use)
|
|
360
360
|
// Tests can inject a mock modelProvider via constructor options
|
|
361
361
|
if (!this.modelProviderInjected) {
|
|
@@ -409,6 +409,75 @@ export class AgentHarness {
|
|
|
409
409
|
return this.dispatcher.list();
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
/**
|
|
413
|
+
* Wraps the run() generator with Latitude telemetry capture for complete trace coverage
|
|
414
|
+
* Streams events in real-time using an event queue pattern
|
|
415
|
+
*/
|
|
416
|
+
async *runWithTelemetry(input: RunInput): AsyncGenerator<AgentEvent> {
|
|
417
|
+
const config = this.loadedConfig;
|
|
418
|
+
const telemetryEnabled = config?.telemetry?.enabled !== false;
|
|
419
|
+
const latitudeApiKey = config?.telemetry?.latitude?.apiKey;
|
|
420
|
+
const rawProjectId = config?.telemetry?.latitude?.projectId;
|
|
421
|
+
const projectId = typeof rawProjectId === 'string' ? parseInt(rawProjectId, 10) : rawProjectId;
|
|
422
|
+
const path = config?.telemetry?.latitude?.path ?? this.parsedAgent?.frontmatter.name ?? 'agent';
|
|
423
|
+
|
|
424
|
+
// If Latitude telemetry is configured, wrap the entire run with capture
|
|
425
|
+
if (telemetryEnabled && latitudeApiKey && projectId) {
|
|
426
|
+
const telemetry = new LatitudeTelemetry(latitudeApiKey);
|
|
427
|
+
|
|
428
|
+
// Event queue for streaming events in real-time
|
|
429
|
+
const eventQueue: AgentEvent[] = [];
|
|
430
|
+
let queueResolve: ((value: void) => void) | null = null;
|
|
431
|
+
let generatorDone = false;
|
|
432
|
+
let generatorError: Error | null = null;
|
|
433
|
+
|
|
434
|
+
// Start the generator inside telemetry.capture() (runs in background)
|
|
435
|
+
const capturePromise = telemetry.capture({ projectId, path }, async () => {
|
|
436
|
+
try {
|
|
437
|
+
for await (const event of this.run(input)) {
|
|
438
|
+
eventQueue.push(event);
|
|
439
|
+
if (queueResolve) {
|
|
440
|
+
const resolve = queueResolve;
|
|
441
|
+
queueResolve = null;
|
|
442
|
+
resolve();
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
} catch (error) {
|
|
446
|
+
generatorError = error as Error;
|
|
447
|
+
} finally {
|
|
448
|
+
generatorDone = true;
|
|
449
|
+
if (queueResolve) {
|
|
450
|
+
queueResolve();
|
|
451
|
+
queueResolve = null;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
// Yield events from the queue as they arrive
|
|
457
|
+
try {
|
|
458
|
+
while (!generatorDone || eventQueue.length > 0) {
|
|
459
|
+
if (eventQueue.length > 0) {
|
|
460
|
+
yield eventQueue.shift()!;
|
|
461
|
+
} else if (!generatorDone) {
|
|
462
|
+
// Wait for next event
|
|
463
|
+
await new Promise<void>((resolve) => {
|
|
464
|
+
queueResolve = resolve;
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
if (generatorError) {
|
|
470
|
+
throw generatorError;
|
|
471
|
+
}
|
|
472
|
+
} finally {
|
|
473
|
+
await capturePromise;
|
|
474
|
+
}
|
|
475
|
+
} else {
|
|
476
|
+
// No telemetry configured, just pass through
|
|
477
|
+
yield* this.run(input);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
412
481
|
async *run(input: RunInput): AsyncGenerator<AgentEvent> {
|
|
413
482
|
if (!this.parsedAgent) {
|
|
414
483
|
await this.initialize();
|
|
@@ -588,14 +657,20 @@ ${boundedMainMemory.trim()}`
|
|
|
588
657
|
const temperature = agent.frontmatter.model?.temperature ?? 0.2;
|
|
589
658
|
const maxTokens = agent.frontmatter.model?.maxTokens ?? 1024;
|
|
590
659
|
|
|
591
|
-
// Stream response using Vercel AI SDK
|
|
660
|
+
// Stream response using Vercel AI SDK with telemetry enabled
|
|
661
|
+
const telemetryEnabled = this.loadedConfig?.telemetry?.enabled !== false;
|
|
662
|
+
const latitudeApiKey = this.loadedConfig?.telemetry?.latitude?.apiKey;
|
|
663
|
+
|
|
592
664
|
const result = await streamText({
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
665
|
+
model: this.modelProvider(modelName),
|
|
666
|
+
system: integrityPrompt,
|
|
667
|
+
messages: coreMessages,
|
|
668
|
+
tools,
|
|
669
|
+
temperature,
|
|
670
|
+
maxTokens,
|
|
671
|
+
experimental_telemetry: {
|
|
672
|
+
isEnabled: telemetryEnabled && !!latitudeApiKey,
|
|
673
|
+
},
|
|
599
674
|
});
|
|
600
675
|
|
|
601
676
|
// Stream text chunks
|