@poncho-ai/harness 0.59.18 → 0.59.19

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.59.18 build /home/runner/work/poncho-ai/poncho-ai/packages/harness
2
+ > @poncho-ai/harness@0.59.19 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,9 +8,9 @@
8
8
  CLI tsup v8.5.1
9
9
  CLI Target: es2022
10
10
  ESM Build start
11
- ESM dist/index.js 572.34 KB
12
11
  ESM dist/isolate-F2PPSUL6.js 53.82 KB
13
- ESM ⚡️ Build success in 214ms
12
+ ESM dist/index.js 572.59 KB
13
+ ESM ⚡️ Build success in 249ms
14
14
  DTS Build start
15
- DTS ⚡️ Build success in 7534ms
16
- DTS dist/index.d.ts 104.01 KB
15
+ DTS ⚡️ Build success in 7835ms
16
+ DTS dist/index.d.ts 104.09 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @poncho-ai/harness
2
2
 
3
+ ## 0.59.19
4
+
5
+ ### Patch Changes
6
+
7
+ - [#186](https://github.com/cesr/poncho-ai/pull/186) [`b12ccbf`](https://github.com/cesr/poncho-ai/commit/b12ccbf1de63a5ef996b0896898c2afe7238a271) Thanks [@cesr](https://github.com/cesr)! - Stamp the tool-call id onto completed-tool activity lines (`{tcid:<id>}`
8
+ appended after any human detail). Display clients can now join a tool pill to
9
+ its full input/output by id instead of by tool-name + position. The old
10
+ positional/name match misaligns whenever parallel tool calls in a turn
11
+ complete out of declaration order, and can never reach a subagent's
12
+ inner-tool results; id-joining fixes both. The token sits after the first
13
+ `(...)` detail group, so existing clients that only parse inside it are
14
+ unaffected, and it is stripped from model-visible interruption text via the
15
+ new `stripPillMetaTokens` export.
16
+
3
17
  ## 0.59.18
4
18
 
5
19
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -2135,6 +2135,7 @@ declare const flushTurnDraft: (draft: TurnDraftState) => void;
2135
2135
  declare const buildToolCompletedText: (event: AgentEvent & {
2136
2136
  type: "tool:completed";
2137
2137
  }) => string;
2138
+ declare const stripPillMetaTokens: (line: string) => string;
2138
2139
  declare const recordStandardTurnEvent: (draft: TurnDraftState, event: AgentEvent) => void;
2139
2140
  declare const buildAssistantMetadata: (draft: TurnDraftState, sectionsOverride?: TurnSection[], opts?: {
2140
2141
  id?: string;
@@ -2418,4 +2419,4 @@ type NewEntryNoId = NewConversationEntry extends infer T ? T extends NewConversa
2418
2419
  */
2419
2420
  declare const appendEntriesSafe: (store: ConversationStore, conversation: Pick<Conversation, "conversationId" | "ownerId" | "tenantId">, entries: NewEntryNoId[], log: Logger) => Promise<ConversationEntry[]>;
2420
2421
 
2421
- export { type ActiveConversationRun, type ActiveSubagentRun, type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, AgentOrchestrator, type ApprovalEventItem, type ArchivedToolResult$1 as ArchivedToolResult, type BashConfig, BashEnvironmentManager, type BashExecutionLimits, type BuiltInToolToggles, CALLBACK_LOCK_STALE_MS, type CallbackStartedEntry, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type ContinuationHooks, type Conversation, type ConversationCreateInit, type ConversationEntry, type ConversationState, type ConversationStatusSnapshot, type ConversationStore, type ConversationSummary, type CreateSkillToolsOptions, type CronJobConfig, DEFAULT_AGENT_DESCRIPTION, DEFAULT_AGENT_NAME, DEFAULT_MAX_STEPS, DEFAULT_MODEL_NAME, DEFAULT_MODEL_PROVIDER, DEFAULT_TAGLINE, DEFAULT_TEMPERATURE, DEFAULT_TIMEOUT, type DefaultAgentDefinitionOptions, type EventSink, type ExecuteTurnResult, type HarnessOptions, type HarnessRunOutput, type HistorySource, InMemoryConversationStore, InMemoryEngine, InMemoryStateStore, type IsolateBinding, type IsolateConfig, LocalMcpBridge, LocalUploadStore, MAX_CONCURRENT_SUBAGENTS, MAX_CONTINUATION_COUNT, MAX_SUBAGENT_CALLBACK_COUNT, MAX_SUBAGENT_NESTING, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, type MountProvider, type NetworkConfig, type NewConversationEntry, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OrchestratorHooks, type OrchestratorOptions, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentApproval, type PendingSubagentResult, type PendingToolCall, type PonchoConfig, PonchoFsAdapter, PostgresEngine, type ProviderConfig, type Recurrence, type RecurrenceType, type Reminder, type ReminderCreateInput, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RunConversationTurnOpts, type RunConversationTurnResult, type RunOutcome, type RunRequest, type RuntimeRenderContext, S3UploadStore, STALE_SUBAGENT_THRESHOLD_MS, STORAGE_SCHEMA_VERSION, type SecretsStore, type SkillContextEntry, type SkillMetadata, type SkillSource, SqliteEngine, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type StorageEngine, type StorageFactoryOptions, type StorageProvider, type StoredApproval, type SubagentManager, type SubagentResult, type SubagentResultEntry, type SubagentSpawnResult, type SubagentSummary, type SubagentTranscript, type SubagentTranscriptMode, TOOL_RESULT_ARCHIVE_PARAM, type TelemetryConfig, TelemetryEmitter, type TenantTokenPayload, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type TurnDraftState, type TurnResultMetadata, type TurnSection, type UploadStore, type UploadsConfig, VFS_SCHEME, VercelBlobUploadStore, type VfsDirEntry, type VfsStat, type VirtualMount, abnormalEndResponse, appendEntriesSafe, applyTurnMetadata, buildAgentDirectoryName, buildApprovalCheckpoints, buildAssistantMetadata, buildSkillContextWindow, buildToolCompletedText, cloneSections, compactMessages, completeOpenAICodexDeviceAuth, computeNextOccurrence, createBashTool, createConversationStore, createConversationStoreFromEngine, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryStoreFromEngine, createMemoryTools, createModelProvider, createReminderStore, createReminderStoreFromEngine, createReminderTools, createSearchTools, createSecretsStore, createSkillTools, createStateStore, createStorageEngine, createSubagentTools, createTodoStoreFromEngine, createTurnDraftState, createUploadStore, createWriteTool, decodeFileInputData, defaultAgentDefinition, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, executeConversationTurn, findSafeSplitPoint, flushTurnDraft, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPendingSubagentResults, getPonchoStoreRoot, isMessageArray, jsonSchemaToZod, lastAssistantText, loadCanonicalHistory, loadPonchoConfig, loadRunHistory, loadSkillContext, loadSkillInstructions, loadSkillMetadata, loadSkillMetadataFromDirs, loadVfsSkillMetadata, mergeSkills, normalizeApprovalCheckpoint, normalizeOtlp, normalizeScriptPolicyPath, normalizeToolAccess, parseAgentFile, parseAgentMarkdown, parseSkillFrontmatter, ponchoDocsTool, readOpenAICodexSession, readSkillResource, realResponseText, recordStandardTurnEvent, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveEnv, resolveMemoryConfig, resolveRunRequest, resolveSkillDirs, resolveStateConfig, runConversationTurn, slugifyStorageComponent, startOpenAICodexDeviceAuth, verifyTenantToken, withToolResultArchiveParam, writeOpenAICodexSession };
2422
+ export { type ActiveConversationRun, type ActiveSubagentRun, type AgentFrontmatter, AgentHarness, type AgentIdentity, type AgentLimitsConfig, type AgentModelConfig, AgentOrchestrator, type ApprovalEventItem, type ArchivedToolResult$1 as ArchivedToolResult, type BashConfig, BashEnvironmentManager, type BashExecutionLimits, type BuiltInToolToggles, CALLBACK_LOCK_STALE_MS, type CallbackStartedEntry, type CompactMessagesOptions, type CompactResult, type CompactionConfig, type ContinuationHooks, type Conversation, type ConversationCreateInit, type ConversationEntry, type ConversationState, type ConversationStatusSnapshot, type ConversationStore, type ConversationSummary, type CreateSkillToolsOptions, type CronJobConfig, DEFAULT_AGENT_DESCRIPTION, DEFAULT_AGENT_NAME, DEFAULT_MAX_STEPS, DEFAULT_MODEL_NAME, DEFAULT_MODEL_PROVIDER, DEFAULT_TAGLINE, DEFAULT_TEMPERATURE, DEFAULT_TIMEOUT, type DefaultAgentDefinitionOptions, type EventSink, type ExecuteTurnResult, type HarnessOptions, type HarnessRunOutput, type HistorySource, InMemoryConversationStore, InMemoryEngine, InMemoryStateStore, type IsolateBinding, type IsolateConfig, LocalMcpBridge, LocalUploadStore, MAX_CONCURRENT_SUBAGENTS, MAX_CONTINUATION_COUNT, MAX_SUBAGENT_CALLBACK_COUNT, MAX_SUBAGENT_NESTING, type MainMemory, type McpConfig, type MemoryConfig, type MemoryStore, type MessagingChannelConfig, type ModelProviderFactory, type MountProvider, type NetworkConfig, type NewConversationEntry, OPENAI_CODEX_CLIENT_ID, type OpenAICodexAuthConfig, type OpenAICodexDeviceAuthRequest, type OpenAICodexSession, type OrchestratorHooks, type OrchestratorOptions, type OtlpConfig, type OtlpOption, PONCHO_UPLOAD_SCHEME, type ParsedAgent, type PendingSubagentApproval, type PendingSubagentResult, type PendingToolCall, type PonchoConfig, PonchoFsAdapter, PostgresEngine, type ProviderConfig, type Recurrence, type RecurrenceType, type Reminder, type ReminderCreateInput, type ReminderStatus, type ReminderStore, type RemoteMcpServerConfig, type RunConversationTurnOpts, type RunConversationTurnResult, type RunOutcome, type RunRequest, type RuntimeRenderContext, S3UploadStore, STALE_SUBAGENT_THRESHOLD_MS, STORAGE_SCHEMA_VERSION, type SecretsStore, type SkillContextEntry, type SkillMetadata, type SkillSource, SqliteEngine, type StateConfig, type StateProviderName, type StateStore, type StorageConfig, type StorageEngine, type StorageFactoryOptions, type StorageProvider, type StoredApproval, type SubagentManager, type SubagentResult, type SubagentResultEntry, type SubagentSpawnResult, type SubagentSummary, type SubagentTranscript, type SubagentTranscriptMode, TOOL_RESULT_ARCHIVE_PARAM, type TelemetryConfig, TelemetryEmitter, type TenantTokenPayload, type ToolAccess, type ToolCall, ToolDispatcher, type ToolExecutionResult, type TurnDraftState, type TurnResultMetadata, type TurnSection, type UploadStore, type UploadsConfig, VFS_SCHEME, VercelBlobUploadStore, type VfsDirEntry, type VfsStat, type VirtualMount, abnormalEndResponse, appendEntriesSafe, applyTurnMetadata, buildAgentDirectoryName, buildApprovalCheckpoints, buildAssistantMetadata, buildSkillContextWindow, buildToolCompletedText, cloneSections, compactMessages, completeOpenAICodexDeviceAuth, computeNextOccurrence, createBashTool, createConversationStore, createConversationStoreFromEngine, createDefaultTools, createDeleteDirectoryTool, createDeleteTool, createEditTool, createMemoryStore, createMemoryStoreFromEngine, createMemoryTools, createModelProvider, createReminderStore, createReminderStoreFromEngine, createReminderTools, createSearchTools, createSecretsStore, createSkillTools, createStateStore, createStorageEngine, createSubagentTools, createTodoStoreFromEngine, createTurnDraftState, createUploadStore, createWriteTool, decodeFileInputData, defaultAgentDefinition, deleteOpenAICodexSession, deriveUploadKey, ensureAgentIdentity, estimateTokens, estimateTotalTokens, executeConversationTurn, findSafeSplitPoint, flushTurnDraft, generateAgentId, getAgentStoreDirectory, getModelContextWindow, getOpenAICodexAccessToken, getOpenAICodexAuthFilePath, getOpenAICodexRequiredScopes, getPendingSubagentResults, getPonchoStoreRoot, isMessageArray, jsonSchemaToZod, lastAssistantText, loadCanonicalHistory, loadPonchoConfig, loadRunHistory, loadSkillContext, loadSkillInstructions, loadSkillMetadata, loadSkillMetadataFromDirs, loadVfsSkillMetadata, mergeSkills, normalizeApprovalCheckpoint, normalizeOtlp, normalizeScriptPolicyPath, normalizeToolAccess, parseAgentFile, parseAgentMarkdown, parseSkillFrontmatter, ponchoDocsTool, readOpenAICodexSession, readSkillResource, realResponseText, recordStandardTurnEvent, renderAgentPrompt, resolveAgentIdentity, resolveCompactionConfig, resolveEnv, resolveMemoryConfig, resolveRunRequest, resolveSkillDirs, resolveStateConfig, runConversationTurn, slugifyStorageComponent, startOpenAICodexDeviceAuth, stripPillMetaTokens, verifyTenantToken, withToolResultArchiveParam, writeOpenAICodexSession };
package/dist/index.js CHANGED
@@ -12739,8 +12739,10 @@ var buildToolCompletedText = (event) => {
12739
12739
  if (event.tool === "web_search" && Array.isArray(output?.results)) {
12740
12740
  text += ` \u2014 ${output.results.length} result${output.results.length !== 1 ? "s" : ""}`;
12741
12741
  }
12742
+ if (event.toolCallId) text += ` {tcid:${event.toolCallId}}`;
12742
12743
  return text;
12743
12744
  };
12745
+ var stripPillMetaTokens = (line) => line.replace(/\s*\{tcid:[^}]+\}/g, "");
12744
12746
  var recordStandardTurnEvent = (draft, event) => {
12745
12747
  if (event.type === "model:chunk") {
12746
12748
  if (draft.currentTools.length > 0) {
@@ -13622,7 +13624,7 @@ var AgentOrchestrator = class {
13622
13624
  for (const a of decidedApprovals) {
13623
13625
  if (a.decision === "approved" && a.toolCallId) {
13624
13626
  callsToExecute.push({ id: a.toolCallId, name: a.tool, input: a.input });
13625
- const toolText = `- done \`${a.tool}\``;
13627
+ const toolText = `- done \`${a.tool}\`` + (a.toolCallId ? ` {tcid:${a.toolCallId}}` : "");
13626
13628
  draft.toolTimeline.push(toolText);
13627
13629
  draft.currentTools.push(toolText);
13628
13630
  } else if (a.toolCallId) {
@@ -14783,8 +14785,10 @@ var runConversationTurn = async (opts) => {
14783
14785
  const parts = [];
14784
14786
  if (draft.assistantResponse.length > 0) parts.push(draft.assistantResponse);
14785
14787
  if (draft.toolTimeline.length > 0) {
14786
- parts.push(`Tool activity before interruption:
14787
- ${draft.toolTimeline.join("\n")}`);
14788
+ parts.push(
14789
+ `Tool activity before interruption:
14790
+ ${draft.toolTimeline.map(stripPillMetaTokens).join("\n")}`
14791
+ );
14788
14792
  }
14789
14793
  parts.push(`[This turn was interrupted: ${reason}. The work above may be incomplete.]`);
14790
14794
  return [
@@ -14991,6 +14995,7 @@ export {
14991
14995
  runConversationTurn,
14992
14996
  slugifyStorageComponent,
14993
14997
  startOpenAICodexDeviceAuth,
14998
+ stripPillMetaTokens,
14994
14999
  verifyTenantToken,
14995
15000
  withToolResultArchiveParam,
14996
15001
  writeOpenAICodexSession
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poncho-ai/harness",
3
- "version": "0.59.18",
3
+ "version": "0.59.19",
4
4
  "description": "Agent execution runtime - conversation loop, tool dispatch, streaming",
5
5
  "repository": {
6
6
  "type": "git",
@@ -13,6 +13,7 @@ export {
13
13
  cloneSections,
14
14
  flushTurnDraft,
15
15
  buildToolCompletedText,
16
+ stripPillMetaTokens,
16
17
  recordStandardTurnEvent,
17
18
  buildAssistantMetadata,
18
19
  executeConversationTurn,
@@ -904,7 +904,8 @@ export class AgentOrchestrator {
904
904
  for (const a of decidedApprovals) {
905
905
  if (a.decision === "approved" && a.toolCallId) {
906
906
  callsToExecute.push({ id: a.toolCallId, name: a.tool, input: a.input });
907
- const toolText = `- done \`${a.tool}\``;
907
+ const toolText =
908
+ `- done \`${a.tool}\`` + (a.toolCallId ? ` {tcid:${a.toolCallId}}` : "");
908
909
  draft.toolTimeline.push(toolText);
909
910
  draft.currentTools.push(toolText);
910
911
  } else if (a.toolCallId) {
@@ -35,6 +35,7 @@ import {
35
35
  createTurnDraftState,
36
36
  executeConversationTurn,
37
37
  flushTurnDraft,
38
+ stripPillMetaTokens,
38
39
  } from "./turn.js";
39
40
 
40
41
  const log = createLogger("orchestrator");
@@ -435,7 +436,11 @@ export const runConversationTurn = async (
435
436
  const parts: string[] = [];
436
437
  if (draft.assistantResponse.length > 0) parts.push(draft.assistantResponse);
437
438
  if (draft.toolTimeline.length > 0) {
438
- parts.push(`Tool activity before interruption:\n${draft.toolTimeline.join("\n")}`);
439
+ parts.push(
440
+ `Tool activity before interruption:\n${draft.toolTimeline
441
+ .map(stripPillMetaTokens)
442
+ .join("\n")}`,
443
+ );
439
444
  }
440
445
  parts.push(`[This turn was interrupted: ${reason}. The work above may be incomplete.]`);
441
446
  return [
@@ -120,9 +120,25 @@ export const buildToolCompletedText = (event: AgentEvent & { type: "tool:complet
120
120
  text += ` \u2014 ${(output.results as unknown[]).length} result${(output.results as unknown[]).length !== 1 ? "s" : ""}`;
121
121
  }
122
122
 
123
+ // Trailing machine token: the tool-call id this pill corresponds to. Lets a
124
+ // display client join the pill to its full input/output by id rather than
125
+ // by tool-name+position (which misaligns whenever parallel tool calls in a
126
+ // turn complete out of declaration order, and can't reach a subagent's
127
+ // inner-tool results at all). Appended AFTER any human detail/parens so
128
+ // older clients \u2014 which only read inside the first `(...)` \u2014 ignore it.
129
+ // Stripped from model-visible interruption text via stripPillMetaTokens.
130
+ if (event.toolCallId) text += ` {tcid:${event.toolCallId}}`;
131
+
123
132
  return text;
124
133
  };
125
134
 
135
+ // Remove machine tokens (e.g. `{tcid:\u2026}`) that buildToolCompletedText appends
136
+ // to activity lines for the display client. Use anywhere a tool-timeline line
137
+ // is folded into MODEL-visible text (e.g. interruption reconstruction) so the
138
+ // internal id never leaks into the prompt.
139
+ export const stripPillMetaTokens = (line: string): string =>
140
+ line.replace(/\s*\{tcid:[^}]+\}/g, "");
141
+
126
142
  export const recordStandardTurnEvent = (draft: TurnDraftState, event: AgentEvent): void => {
127
143
  if (event.type === "model:chunk") {
128
144
  if (draft.currentTools.length > 0) {
@@ -0,0 +1,56 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import type { AgentEvent } from "@poncho-ai/sdk";
3
+ import { buildToolCompletedText, stripPillMetaTokens } from "../src/orchestrator/turn.js";
4
+
5
+ const completed = (over: Partial<AgentEvent & { type: "tool:completed" }>) =>
6
+ buildToolCompletedText({
7
+ type: "tool:completed",
8
+ tool: "bash",
9
+ toolCallId: "toolu_abc123",
10
+ input: { command: "ls -la" },
11
+ output: {},
12
+ duration: 45,
13
+ outputTokenEstimate: 0,
14
+ ...over,
15
+ } as AgentEvent & { type: "tool:completed" });
16
+
17
+ describe("buildToolCompletedText tcid token", () => {
18
+ it("appends the tool-call id after the human detail", () => {
19
+ const line = completed({});
20
+ expect(line).toContain("- done `bash`");
21
+ expect(line).toContain("(45ms, ls -la)");
22
+ expect(line.endsWith("{tcid:toolu_abc123}")).toBe(true);
23
+ // Token sits AFTER the first (...) detail group so old clients ignore it.
24
+ expect(line.indexOf("{tcid:")).toBeGreaterThan(line.indexOf(")"));
25
+ });
26
+
27
+ it("omits the token when there is no tool-call id", () => {
28
+ const line = completed({ toolCallId: undefined as unknown as string });
29
+ expect(line).not.toContain("{tcid:");
30
+ });
31
+
32
+ it("keeps the id intact alongside the subagent token", () => {
33
+ const line = completed({
34
+ tool: "spawn_subagent",
35
+ toolCallId: "toolu_xyz",
36
+ input: { task: "research" },
37
+ output: { subagentId: "conv_child" },
38
+ });
39
+ expect(line).toContain("[subagent:conv_child]");
40
+ expect(line).toContain("{tcid:toolu_xyz}");
41
+ });
42
+ });
43
+
44
+ describe("stripPillMetaTokens", () => {
45
+ it("removes the tcid token (and its leading space) for model-visible text", () => {
46
+ expect(stripPillMetaTokens("- done `bash` (45ms, ls) {tcid:toolu_abc}")).toBe(
47
+ "- done `bash` (45ms, ls)",
48
+ );
49
+ });
50
+
51
+ it("is a no-op for lines without a token", () => {
52
+ expect(stripPillMetaTokens("- start `web_search` (\"q\")")).toBe(
53
+ "- start `web_search` (\"q\")",
54
+ );
55
+ });
56
+ });