@oh-my-pi/pi-coding-agent 17.2.10 → 17.2.12
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/CHANGELOG.md +53 -0
- package/dist/{CHANGELOG-rhwzpexa.md → CHANGELOG-k9ghy5sn.md} +53 -0
- package/dist/cli.js +10775 -10762
- package/dist/types/advisor/runtime.d.ts +1 -1
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/custom-models.d.ts +31 -0
- package/dist/types/config/model-config-values.d.ts +19 -0
- package/dist/types/config/model-patch.d.ts +93 -0
- package/dist/types/config/model-provider-discovery.d.ts +51 -0
- package/dist/types/config/model-registry.d.ts +9 -52
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/config/settings.d.ts +5 -3
- package/dist/types/debug/raw-sse-buffer.d.ts +9 -0
- package/dist/types/discovery/agent-plugin-format.d.ts +136 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +33 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/eval/executor-base.d.ts +8 -2
- package/dist/types/eval/kernel-session-registry.d.ts +60 -0
- package/dist/types/export/share.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +7 -0
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/lsp/diagnostics.d.ts +96 -0
- package/dist/types/lsp/index.d.ts +7 -128
- package/dist/types/lsp/servers.d.ts +72 -0
- package/dist/types/lsp/tool.d.ts +42 -0
- package/dist/types/lsp/workspace-diagnostics.d.ts +12 -0
- package/dist/types/lsp/writethrough.d.ts +33 -0
- package/dist/types/mcp/transports/header-policy.d.ts +46 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/components/agent-hub-projection.d.ts +2 -7
- package/dist/types/modes/components/agent-hub-renderer.d.ts +0 -7
- package/dist/types/modes/components/agent-hub.d.ts +2 -0
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/theme/color.d.ts +19 -0
- package/dist/types/modes/theme/loader.d.ts +19 -0
- package/dist/types/modes/theme/schema.d.ts +175 -0
- package/dist/types/modes/theme/symbols.d.ts +28 -0
- package/dist/types/modes/theme/theme-class.d.ts +244 -0
- package/dist/types/modes/theme/theme.d.ts +9 -280
- package/dist/types/modes/theme/tui-adapters.d.ts +13 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +1 -3
- package/dist/types/secrets/index.d.ts +26 -2
- package/dist/types/secrets/message-transform.d.ts +40 -0
- package/dist/types/secrets/obfuscator.d.ts +0 -108
- package/dist/types/secrets/placeholder-scan.d.ts +95 -0
- package/dist/types/secrets/placeholder.d.ts +94 -0
- package/dist/types/secrets/replacement.d.ts +82 -0
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session-types.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +2 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-handoff.d.ts +3 -3
- package/dist/types/session/session-manager.d.ts +32 -0
- package/dist/types/session/session-provider-boundary.d.ts +1 -1
- package/dist/types/session/session-tools.d.ts +8 -0
- package/dist/types/session/turn-recovery.d.ts +9 -4
- package/dist/types/slash-commands/builtin-collaboration.d.ts +2 -0
- package/dist/types/slash-commands/builtin-completions.d.ts +36 -0
- package/dist/types/slash-commands/builtin-control.d.ts +2 -0
- package/dist/types/slash-commands/builtin-lifecycle.d.ts +3 -0
- package/dist/types/slash-commands/builtin-marketplace.d.ts +11 -0
- package/dist/types/slash-commands/builtin-modes.d.ts +5 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/slash-commands/builtin-session.d.ts +2 -0
- package/dist/types/task/index.d.ts +2 -0
- package/dist/types/tools/gh-common.d.ts +69 -0
- package/dist/types/tools/gh-pr-checkout.d.ts +84 -0
- package/dist/types/tools/gh-pr-diff.d.ts +102 -0
- package/dist/types/tools/gh-run-watch.d.ts +78 -0
- package/dist/types/tools/gh-search.d.ts +61 -0
- package/dist/types/tools/gh-types.d.ts +340 -0
- package/dist/types/tools/gh-view.d.ts +88 -0
- package/dist/types/tools/gh.d.ts +4 -201
- package/dist/types/tools/read-archive.d.ts +16 -0
- package/dist/types/tools/read-format.d.ts +104 -0
- package/dist/types/tools/read-path-resolution.d.ts +19 -0
- package/dist/types/tools/read-pdf-images.d.ts +12 -0
- package/dist/types/tools/read-renderer.d.ts +24 -0
- package/dist/types/tools/read-selector.d.ts +27 -0
- package/dist/types/tools/read-sqlite.d.ts +16 -0
- package/dist/types/tools/read-summary.d.ts +19 -0
- package/dist/types/tools/read.d.ts +1 -23
- package/dist/types/tools/shell-tokenize.d.ts +18 -1
- package/dist/types/utils/changelog.d.ts +0 -5
- package/package.json +13 -13
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +12 -7
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/command-help.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/share.ts +71 -0
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/custom-models.ts +188 -0
- package/src/config/model-config-values.ts +128 -0
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-patch.ts +252 -0
- package/src/config/model-provider-discovery.ts +132 -0
- package/src/config/model-registry.ts +84 -704
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +53 -3
- package/src/debug/raw-sse-buffer.ts +20 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +75 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/edit/hashline/diff.ts +5 -1
- package/src/eval/executor-base.ts +39 -6
- package/src/eval/jl/executor.ts +82 -371
- package/src/eval/kernel-session-registry.ts +398 -0
- package/src/eval/py/executor.ts +53 -261
- package/src/eval/rb/executor.ts +36 -279
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/export/share.ts +2 -1
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/loader.ts +78 -14
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +12 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/lsp/diagnostics.ts +516 -0
- package/src/lsp/index.ts +20 -2819
- package/src/lsp/servers.ts +296 -0
- package/src/lsp/tool.ts +1352 -0
- package/src/lsp/workspace-diagnostics.ts +170 -0
- package/src/lsp/writethrough.ts +561 -0
- package/src/main.ts +3 -2
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +15 -4
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +2 -2
- package/src/modes/components/agent-hub-renderer.ts +3 -7
- package/src/modes/components/agent-hub.ts +5 -0
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +6 -4
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +8 -2
- package/src/modes/controllers/event-controller.ts +15 -15
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/theme/color.ts +133 -0
- package/src/modes/theme/loader.ts +178 -0
- package/src/modes/theme/schema.ts +263 -0
- package/src/modes/theme/symbols.ts +1000 -0
- package/src/modes/theme/theme-class.ts +611 -0
- package/src/modes/theme/theme.ts +27 -2453
- package/src/modes/theme/tui-adapters.ts +279 -0
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/registry/agent-registry.ts +2 -2
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +51 -6
- package/src/secrets/message-transform.ts +287 -0
- package/src/secrets/obfuscator.ts +39 -1303
- package/src/secrets/placeholder-scan.ts +506 -0
- package/src/secrets/placeholder.ts +309 -0
- package/src/secrets/replacement.ts +216 -0
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session-types.ts +6 -0
- package/src/session/agent-session.ts +146 -21
- package/src/session/indexed-session-storage.ts +7 -2
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-advisors.ts +32 -34
- package/src/session/session-context.ts +3 -5
- package/src/session/session-handoff.ts +39 -16
- package/src/session/session-manager.ts +67 -3
- package/src/session/session-provider-boundary.ts +3 -6
- package/src/session/session-tools.ts +37 -3
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +115 -84
- package/src/slash-commands/builtin-collaboration.ts +504 -0
- package/src/slash-commands/builtin-completions.ts +291 -0
- package/src/slash-commands/builtin-control.ts +78 -0
- package/src/slash-commands/builtin-lifecycle.ts +506 -0
- package/src/slash-commands/builtin-marketplace.ts +567 -0
- package/src/slash-commands/builtin-modes.ts +518 -0
- package/src/slash-commands/builtin-registry.ts +21 -2996
- package/src/slash-commands/builtin-session.ts +592 -0
- package/src/task/executor.ts +17 -14
- package/src/task/index.ts +21 -6
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +10 -11
- package/src/tools/debug.ts +1 -1
- package/src/tools/gh-common.ts +288 -0
- package/src/tools/gh-pr-checkout.ts +679 -0
- package/src/tools/gh-pr-diff.ts +473 -0
- package/src/tools/gh-run-watch.ts +1015 -0
- package/src/tools/gh-search.ts +500 -0
- package/src/tools/gh-types.ts +379 -0
- package/src/tools/gh-view.ts +612 -0
- package/src/tools/gh.ts +109 -3821
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/read-archive.ts +209 -0
- package/src/tools/read-format.ts +593 -0
- package/src/tools/read-path-resolution.ts +36 -0
- package/src/tools/read-pdf-images.ts +250 -0
- package/src/tools/read-renderer.ts +289 -0
- package/src/tools/read-selector.ts +84 -0
- package/src/tools/read-sqlite.ts +215 -0
- package/src/tools/read-summary.ts +199 -0
- package/src/tools/read.ts +82 -1824
- package/src/tools/shell-tokenize.ts +99 -1
- package/src/utils/changelog.ts +1 -1
- package/src/utils/title-generator.ts +3 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/zai.ts +12 -3
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import type { AssistantMessage, Context, ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai";
|
|
3
|
+
import type { SessionContext } from "../session/session-context";
|
|
4
|
+
import type { JsonValue, SecretObfuscator } from "./obfuscator";
|
|
5
|
+
import { collectJsonRegexSecretValues, mapJsonStrings } from "./placeholder-scan";
|
|
6
|
+
|
|
7
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
8
|
+
// Display restore (inbound, persisted/provider → local display)
|
|
9
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Restore secret placeholders for local display. Only message kinds the model
|
|
13
|
+
* itself authored from obfuscated context carry placeholders — assistant
|
|
14
|
+
* content and the LLM-written branch/compaction summaries. User, developer, and
|
|
15
|
+
* tool-result messages are persisted with their literal text, so operator-authored
|
|
16
|
+
* placeholder-shaped text must survive untouched; those roles are never walked.
|
|
17
|
+
*/
|
|
18
|
+
export function deobfuscateSessionContext(
|
|
19
|
+
sessionContext: SessionContext,
|
|
20
|
+
obfuscator: SecretObfuscator | undefined,
|
|
21
|
+
): SessionContext {
|
|
22
|
+
if (!obfuscator?.hasSecrets()) return sessionContext;
|
|
23
|
+
const messages = deobfuscateAgentMessages(obfuscator, sessionContext.messages);
|
|
24
|
+
return messages === sessionContext.messages ? sessionContext : { ...sessionContext, messages };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function deobfuscateAgentMessages(obfuscator: SecretObfuscator, messages: AgentMessage[]): AgentMessage[] {
|
|
28
|
+
const deob = (text: string): string => obfuscator.deobfuscate(text);
|
|
29
|
+
let changed = false;
|
|
30
|
+
const result = messages.map((message): AgentMessage => {
|
|
31
|
+
switch (message.role) {
|
|
32
|
+
case "assistant": {
|
|
33
|
+
const content = deobfuscateAssistantContent(obfuscator, message.content);
|
|
34
|
+
if (content === message.content) return message;
|
|
35
|
+
changed = true;
|
|
36
|
+
return { ...message, content };
|
|
37
|
+
}
|
|
38
|
+
case "branchSummary": {
|
|
39
|
+
const summary = deob(message.summary);
|
|
40
|
+
if (summary === message.summary) return message;
|
|
41
|
+
changed = true;
|
|
42
|
+
return { ...message, summary };
|
|
43
|
+
}
|
|
44
|
+
case "compactionSummary": {
|
|
45
|
+
const summary = deob(message.summary);
|
|
46
|
+
const shortSummary = message.shortSummary === undefined ? undefined : deob(message.shortSummary);
|
|
47
|
+
const blocks = message.blocks === undefined ? undefined : deobfuscateTextBlocks(obfuscator, message.blocks);
|
|
48
|
+
if (summary === message.summary && shortSummary === message.shortSummary && blocks === message.blocks) {
|
|
49
|
+
return message;
|
|
50
|
+
}
|
|
51
|
+
changed = true;
|
|
52
|
+
return { ...message, summary, shortSummary, blocks };
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
return message;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return changed ? result : messages;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Restore placeholders in assistant content: visible text and tool-call
|
|
63
|
+
* arguments/intent/rawBlock. Thinking and signatures are opaque
|
|
64
|
+
* provider-replay/hidden-reasoning data and pass through byte-identical.
|
|
65
|
+
*/
|
|
66
|
+
export function deobfuscateAssistantContent(
|
|
67
|
+
obfuscator: SecretObfuscator,
|
|
68
|
+
content: AssistantMessage["content"],
|
|
69
|
+
): AssistantMessage["content"] {
|
|
70
|
+
if (!obfuscator.hasSecrets()) return content;
|
|
71
|
+
const deob = (text: string): string => obfuscator.deobfuscate(text);
|
|
72
|
+
let changed = false;
|
|
73
|
+
const result = content.map((block): AssistantMessage["content"][number] => {
|
|
74
|
+
if (block.type === "text") {
|
|
75
|
+
const text = deob(block.text);
|
|
76
|
+
if (text === block.text) return block;
|
|
77
|
+
changed = true;
|
|
78
|
+
return { ...block, text };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (block.type === "toolCall") {
|
|
82
|
+
const args = deobfuscateToolArguments(obfuscator, block.arguments);
|
|
83
|
+
const intent = block.intent === undefined ? undefined : deob(block.intent);
|
|
84
|
+
const rawBlock = block.rawBlock === undefined ? undefined : deob(block.rawBlock);
|
|
85
|
+
if (args === block.arguments && intent === block.intent && rawBlock === block.rawBlock) return block;
|
|
86
|
+
changed = true;
|
|
87
|
+
return { ...block, arguments: args, intent, rawBlock };
|
|
88
|
+
}
|
|
89
|
+
return block;
|
|
90
|
+
});
|
|
91
|
+
return changed ? result : content;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Restore placeholders inside a tool call's arguments. Arguments are arbitrary
|
|
96
|
+
* model-authored JSON, so tool-call arguments are the ONLY place a recursive
|
|
97
|
+
* JSON walk runs.
|
|
98
|
+
*/
|
|
99
|
+
export function deobfuscateToolArguments(
|
|
100
|
+
obfuscator: SecretObfuscator,
|
|
101
|
+
args: Record<string, unknown>,
|
|
102
|
+
): Record<string, unknown> {
|
|
103
|
+
if (!obfuscator.hasSecrets()) return args;
|
|
104
|
+
return mapJsonStrings(args as JsonValue, s => obfuscator.deobfuscate(s)) as Record<string, unknown>;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/** Redact secrets inside a tool call's arguments (same JSON-walk exception as {@link deobfuscateToolArguments}). */
|
|
108
|
+
export function obfuscateToolArguments(
|
|
109
|
+
obfuscator: SecretObfuscator,
|
|
110
|
+
args: Record<string, unknown>,
|
|
111
|
+
sharedRegexSecretValues?: ReadonlySet<string>,
|
|
112
|
+
): Record<string, unknown> {
|
|
113
|
+
if (!obfuscator.hasSecrets()) return args;
|
|
114
|
+
const regexSecretValues = sharedRegexSecretValues ?? collectJsonRegexSecretValues(obfuscator, args as JsonValue);
|
|
115
|
+
return mapJsonStrings(args as JsonValue, s => obfuscator.obfuscate(s, regexSecretValues)) as Record<string, unknown>;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
119
|
+
// Outbound obfuscation (local → provider)
|
|
120
|
+
// ═══════════════════════════════════════════════════════════════════════════
|
|
121
|
+
|
|
122
|
+
type UserFacingMessage = Extract<Message, { role: "user" | "developer" | "toolResult" }>;
|
|
123
|
+
|
|
124
|
+
/** Obfuscate `text` blocks of a content array; image and other blocks pass through. */
|
|
125
|
+
function obfuscateTextBlocks(
|
|
126
|
+
obfuscator: SecretObfuscator,
|
|
127
|
+
content: (TextContent | ImageContent)[],
|
|
128
|
+
sharedRegexSecretValues?: ReadonlySet<string>,
|
|
129
|
+
): (TextContent | ImageContent)[] {
|
|
130
|
+
let changed = false;
|
|
131
|
+
const result = content.map((block): TextContent | ImageContent => {
|
|
132
|
+
if (block.type !== "text") return block;
|
|
133
|
+
const text = obfuscator.obfuscate(block.text, sharedRegexSecretValues);
|
|
134
|
+
if (text === block.text) return block;
|
|
135
|
+
changed = true;
|
|
136
|
+
return { ...block, text };
|
|
137
|
+
});
|
|
138
|
+
return changed ? result : content;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Restore placeholders in `text` blocks of a content array; image and other blocks pass through. */
|
|
142
|
+
function deobfuscateTextBlocks(
|
|
143
|
+
obfuscator: SecretObfuscator,
|
|
144
|
+
content: (TextContent | ImageContent)[],
|
|
145
|
+
): (TextContent | ImageContent)[] {
|
|
146
|
+
let changed = false;
|
|
147
|
+
const result = content.map((block): TextContent | ImageContent => {
|
|
148
|
+
if (block.type !== "text") return block;
|
|
149
|
+
const text = obfuscator.deobfuscate(block.text);
|
|
150
|
+
if (text === block.text) return block;
|
|
151
|
+
changed = true;
|
|
152
|
+
return { ...block, text };
|
|
153
|
+
});
|
|
154
|
+
return changed ? result : content;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Re-obfuscate assistant content before it returns to a provider after session
|
|
159
|
+
* restoration, removing friendly prefixes made unsafe by this batch. A changed
|
|
160
|
+
* thinking block loses its byte-bound replay signature.
|
|
161
|
+
*/
|
|
162
|
+
function obfuscateAssistantContentForReplay(
|
|
163
|
+
obfuscator: SecretObfuscator,
|
|
164
|
+
content: AssistantMessage["content"],
|
|
165
|
+
sharedRegexSecretValues: ReadonlySet<string>,
|
|
166
|
+
): AssistantMessage["content"] {
|
|
167
|
+
const obfuscate = (text: string): string =>
|
|
168
|
+
obfuscator.stripUnsafeFriendlyPlaceholderPrefixes(
|
|
169
|
+
obfuscator.obfuscate(text, sharedRegexSecretValues),
|
|
170
|
+
sharedRegexSecretValues,
|
|
171
|
+
);
|
|
172
|
+
let changed = false;
|
|
173
|
+
const result = content.map((block): AssistantMessage["content"][number] => {
|
|
174
|
+
if (block.type === "text") {
|
|
175
|
+
const text = obfuscate(block.text);
|
|
176
|
+
if (text === block.text) return block;
|
|
177
|
+
changed = true;
|
|
178
|
+
return { ...block, text };
|
|
179
|
+
}
|
|
180
|
+
if (block.type === "thinking") {
|
|
181
|
+
const thinking = obfuscate(block.thinking);
|
|
182
|
+
if (thinking === block.thinking) return block;
|
|
183
|
+
changed = true;
|
|
184
|
+
return { ...block, thinking, thinkingSignature: undefined };
|
|
185
|
+
}
|
|
186
|
+
if (block.type === "toolCall") {
|
|
187
|
+
const args = mapJsonStrings(block.arguments as JsonValue, obfuscate) as Record<string, unknown>;
|
|
188
|
+
const intent = block.intent === undefined ? undefined : obfuscate(block.intent);
|
|
189
|
+
const rawBlock = block.rawBlock === undefined ? undefined : obfuscate(block.rawBlock);
|
|
190
|
+
if (args === block.arguments && intent === block.intent && rawBlock === block.rawBlock) return block;
|
|
191
|
+
changed = true;
|
|
192
|
+
return { ...block, arguments: args, intent, rawBlock };
|
|
193
|
+
}
|
|
194
|
+
return block;
|
|
195
|
+
});
|
|
196
|
+
return changed ? result : content;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function collectMessageRegexSecretValues(obfuscator: SecretObfuscator, messages: Message[]): Set<string> {
|
|
200
|
+
const values = new Set<string>();
|
|
201
|
+
const addText = (text: string | undefined): void => {
|
|
202
|
+
if (text === undefined) return;
|
|
203
|
+
for (const value of obfuscator.collectRegexSecretValuesForObfuscation(text)) {
|
|
204
|
+
values.add(value);
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
for (const message of messages) {
|
|
208
|
+
if (message.role === "assistant") {
|
|
209
|
+
for (const block of message.content) {
|
|
210
|
+
if (block.type === "text") addText(block.text);
|
|
211
|
+
else if (block.type === "thinking") addText(block.thinking);
|
|
212
|
+
else if (block.type === "toolCall") {
|
|
213
|
+
for (const value of collectJsonRegexSecretValues(obfuscator, block.arguments as JsonValue)) {
|
|
214
|
+
values.add(value);
|
|
215
|
+
}
|
|
216
|
+
addText(block.intent);
|
|
217
|
+
addText(block.rawBlock);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (
|
|
223
|
+
message.role !== "user" &&
|
|
224
|
+
message.role !== "toolResult" &&
|
|
225
|
+
!(message.role === "developer" && message.attribution === "user")
|
|
226
|
+
) {
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const target = message as UserFacingMessage;
|
|
230
|
+
if (typeof target.content === "string") {
|
|
231
|
+
addText(target.content);
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
for (const block of target.content) {
|
|
235
|
+
if (block.type === "text") addText(block.text);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return values;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Redact secrets from outbound messages. User messages, tool results, and
|
|
243
|
+
* user-authored developer messages (e.g. `@file` mentions) are obfuscated.
|
|
244
|
+
* Assistant replay content is re-obfuscated too, because session restoration
|
|
245
|
+
* expands keyed placeholders locally before the next provider request. Inline
|
|
246
|
+
* image bytes are never walked.
|
|
247
|
+
*/
|
|
248
|
+
export function obfuscateMessages(obfuscator: SecretObfuscator, messages: Message[]): Message[] {
|
|
249
|
+
if (!obfuscator.hasSecrets()) return messages;
|
|
250
|
+
const sharedRegexSecretValues = collectMessageRegexSecretValues(obfuscator, messages);
|
|
251
|
+
let changed = false;
|
|
252
|
+
const result = messages.map((message): Message => {
|
|
253
|
+
if (
|
|
254
|
+
message.role !== "user" &&
|
|
255
|
+
message.role !== "toolResult" &&
|
|
256
|
+
!(message.role === "developer" && message.attribution === "user")
|
|
257
|
+
) {
|
|
258
|
+
if (message.role !== "assistant") return message;
|
|
259
|
+
const content = obfuscateAssistantContentForReplay(obfuscator, message.content, sharedRegexSecretValues);
|
|
260
|
+
if (content === message.content) return message;
|
|
261
|
+
changed = true;
|
|
262
|
+
return { ...message, content };
|
|
263
|
+
}
|
|
264
|
+
const target = message as UserFacingMessage;
|
|
265
|
+
if (typeof target.content === "string") {
|
|
266
|
+
const content = obfuscator.obfuscate(target.content, sharedRegexSecretValues);
|
|
267
|
+
if (content === target.content) return message;
|
|
268
|
+
changed = true;
|
|
269
|
+
return { ...target, content } as Message;
|
|
270
|
+
}
|
|
271
|
+
const content = obfuscateTextBlocks(obfuscator, target.content, sharedRegexSecretValues);
|
|
272
|
+
if (content === target.content) return message;
|
|
273
|
+
changed = true;
|
|
274
|
+
return { ...target, content } as Message;
|
|
275
|
+
});
|
|
276
|
+
return changed ? result : messages;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Redact outbound provider context. Only conversation messages are rewritten;
|
|
281
|
+
* the static system prompt and tool schemas pass through unchanged.
|
|
282
|
+
*/
|
|
283
|
+
export function obfuscateProviderContext(obfuscator: SecretObfuscator | undefined, context: Context): Context {
|
|
284
|
+
if (!obfuscator?.hasSecrets()) return context;
|
|
285
|
+
const messages = obfuscateMessages(obfuscator, context.messages);
|
|
286
|
+
return messages === context.messages ? context : { ...context, messages };
|
|
287
|
+
}
|