@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.
- package/.turbo/turbo-build.log +5 -5
- package/CHANGELOG.md +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -3
- package/package.json +1 -1
- package/src/orchestrator/index.ts +1 -0
- package/src/orchestrator/orchestrator.ts +2 -1
- package/src/orchestrator/run-conversation-turn.ts +6 -1
- package/src/orchestrator/turn.ts +16 -0
- package/test/pill-tool-call-id.test.ts +56 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @poncho-ai/harness@0.59.
|
|
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
|
[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[32m572.34 KB[39m
|
|
12
11
|
[32mESM[39m [1mdist/isolate-F2PPSUL6.js [22m[32m53.82 KB[39m
|
|
13
|
-
[32mESM[39m
|
|
12
|
+
[32mESM[39m [1mdist/index.js [22m[32m572.59 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 249ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
|
-
[32mDTS[39m ⚡️ Build success in
|
|
16
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m104.
|
|
15
|
+
[32mDTS[39m ⚡️ Build success in 7835ms
|
|
16
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m104.09 KB[39m
|
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(
|
|
14787
|
-
|
|
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
|
@@ -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 =
|
|
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(
|
|
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 [
|
package/src/orchestrator/turn.ts
CHANGED
|
@@ -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
|
+
});
|