@posthog/agent 2.3.647 → 2.3.656
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/dist/adapters/claude/permissions/permission-options.js +700 -0
- package/dist/adapters/claude/permissions/permission-options.js.map +1 -1
- package/dist/adapters/claude/tools.js +700 -0
- package/dist/adapters/claude/tools.js.map +1 -1
- package/dist/adapters/codex/local-tools-mcp-server.d.ts +2 -0
- package/dist/adapters/codex/local-tools-mcp-server.js +1172 -0
- package/dist/adapters/codex/local-tools-mcp-server.js.map +1 -0
- package/dist/agent.js +1488 -219
- package/dist/agent.js.map +1 -1
- package/dist/execution-mode.js +700 -0
- package/dist/execution-mode.js.map +1 -1
- package/dist/handoff-checkpoint.js.map +1 -1
- package/dist/posthog-api.d.ts +1 -1
- package/dist/posthog-api.js +1 -1
- package/dist/posthog-api.js.map +1 -1
- package/dist/server/agent-server.js +1637 -342
- package/dist/server/agent-server.js.map +1 -1
- package/dist/server/bin.cjs +1553 -261
- package/dist/server/bin.cjs.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/src/adapters/claude/claude-agent.ts +32 -2
- package/src/adapters/claude/hooks.test.ts +54 -0
- package/src/adapters/claude/hooks.ts +86 -0
- package/src/adapters/claude/mcp/local-tools.test.ts +50 -0
- package/src/adapters/claude/mcp/local-tools.ts +40 -0
- package/src/adapters/claude/session/options.ts +14 -9
- package/src/adapters/claude/types.ts +1 -0
- package/src/adapters/codex/codex-agent.ts +117 -22
- package/src/adapters/codex/local-tools-mcp-server.ts +71 -0
- package/src/adapters/local-tools/index.ts +22 -0
- package/src/adapters/local-tools/registry.test.ts +57 -0
- package/src/adapters/local-tools/registry.ts +81 -0
- package/src/adapters/local-tools/tools/signed-commit.ts +26 -0
- package/src/adapters/session-meta.ts +16 -0
- package/src/adapters/signed-commit-shared.ts +82 -0
- package/src/server/agent-server.configure-environment.test.ts +64 -1
- package/src/server/agent-server.test.ts +2 -4
- package/src/server/agent-server.ts +60 -35
- package/src/types.ts +2 -1
- package/src/utils/common.ts +14 -0
- package/src/utils/gateway.test.ts +70 -0
- package/src/utils/gateway.ts +31 -1
|
@@ -900,10 +900,8 @@ describe("AgentServer HTTP Mode", () => {
|
|
|
900
900
|
expect(prompt).toContain(
|
|
901
901
|
"gh pr checkout https://github.com/org/repo/pull/1",
|
|
902
902
|
);
|
|
903
|
-
expect(prompt).toContain(
|
|
904
|
-
|
|
905
|
-
);
|
|
906
|
-
expect(prompt).toContain("Push to the existing PR branch");
|
|
903
|
+
expect(prompt).toContain("git_signed_commit");
|
|
904
|
+
expect(prompt).toContain("Committing (signed commits required)");
|
|
907
905
|
expect(prompt).not.toContain("Create a draft pull request");
|
|
908
906
|
// Review-comment thread handling: reply + resolve
|
|
909
907
|
expect(prompt).toContain("review thread");
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
type AgentErrorClassification,
|
|
26
26
|
classifyAgentError,
|
|
27
27
|
} from "../adapters/error-classification";
|
|
28
|
+
import { SIGNED_COMMIT_QUALIFIED_TOOL_NAME } from "../adapters/signed-commit-shared";
|
|
28
29
|
import type { PermissionMode } from "../execution-mode";
|
|
29
30
|
import { DEFAULT_CODEX_MODEL } from "../gateway-models";
|
|
30
31
|
import { HandoffCheckpointTracker } from "../handoff-checkpoint";
|
|
@@ -47,7 +48,11 @@ import type {
|
|
|
47
48
|
} from "../types";
|
|
48
49
|
import { resourceLink } from "../utils/acp-content";
|
|
49
50
|
import { AsyncMutex } from "../utils/async-mutex";
|
|
50
|
-
import {
|
|
51
|
+
import {
|
|
52
|
+
buildGatewayPropertyHeaders,
|
|
53
|
+
getLlmGatewayUrl,
|
|
54
|
+
resolveGatewayProduct,
|
|
55
|
+
} from "../utils/gateway";
|
|
51
56
|
import { Logger } from "../utils/logger";
|
|
52
57
|
import { logAgentshRuntimeInfo } from "./agentsh-runtime";
|
|
53
58
|
import {
|
|
@@ -844,7 +849,13 @@ export class AgentServer {
|
|
|
844
849
|
}),
|
|
845
850
|
]);
|
|
846
851
|
|
|
847
|
-
this.configureEnvironment({
|
|
852
|
+
this.configureEnvironment({
|
|
853
|
+
isInternal: preTask?.internal === true,
|
|
854
|
+
originProduct: preTask?.origin_product,
|
|
855
|
+
taskId: payload.task_id,
|
|
856
|
+
taskRunId: payload.run_id,
|
|
857
|
+
taskUserId: payload.user_id,
|
|
858
|
+
});
|
|
848
859
|
|
|
849
860
|
const prUrl = getTaskRunStateString(preTaskRun, "slack_notified_pr_url");
|
|
850
861
|
|
|
@@ -949,6 +960,7 @@ export class AgentServer {
|
|
|
949
960
|
_meta: {
|
|
950
961
|
sessionId: payload.run_id,
|
|
951
962
|
taskRunId: payload.run_id,
|
|
963
|
+
taskId: payload.task_id,
|
|
952
964
|
systemPrompt: sessionSystemPrompt,
|
|
953
965
|
...(this.config.model && { model: this.config.model }),
|
|
954
966
|
allowedDomains: this.config.allowedDomains,
|
|
@@ -1599,24 +1611,21 @@ export class AgentServer {
|
|
|
1599
1611
|
private buildCloudSystemPrompt(prUrl?: string | null): string {
|
|
1600
1612
|
const taskId = this.config.taskId;
|
|
1601
1613
|
const shouldAutoCreatePr = this.shouldAutoPublishCloudChanges();
|
|
1602
|
-
const
|
|
1603
|
-
##
|
|
1604
|
-
|
|
1614
|
+
const signedCommitInstructions = `
|
|
1615
|
+
## Committing (signed commits required)
|
|
1616
|
+
Commits MUST be signed. \`git commit\` and \`git push\` are blocked in this environment.
|
|
1617
|
+
To commit: stage your changes with \`git add\`, then call the \`git_signed_commit\` tool (full
|
|
1618
|
+
name \`${SIGNED_COMMIT_QUALIFIED_TOOL_NAME}\`) with a \`message\` (and optional \`body\`/\`paths\`).
|
|
1619
|
+
It creates a GitHub-signed ("Verified") commit on the branch and keeps your local checkout in
|
|
1620
|
+
sync. To start a new branch, pass \`branch\` (prefixed with \`posthog-code/\`) — the tool creates
|
|
1621
|
+
it on the remote for you.
|
|
1605
1622
|
|
|
1606
|
-
|
|
1623
|
+
## Attribution
|
|
1624
|
+
Do NOT add "Co-Authored-By" trailers or "Generated with [Claude Code]" lines to your
|
|
1625
|
+
commit messages. The \`git_signed_commit\` tool automatically appends the only trailers
|
|
1626
|
+
we want:
|
|
1607
1627
|
Generated-By: PostHog Code
|
|
1608
|
-
Task-Id: ${taskId}
|
|
1609
|
-
|
|
1610
|
-
Example:
|
|
1611
|
-
\`\`\`
|
|
1612
|
-
git commit -m "$(cat <<'EOF'
|
|
1613
|
-
fix: resolve login redirect loop
|
|
1614
|
-
|
|
1615
|
-
Generated-By: PostHog Code
|
|
1616
|
-
Task-Id: ${taskId}
|
|
1617
|
-
EOF
|
|
1618
|
-
)"
|
|
1619
|
-
\`\`\``;
|
|
1628
|
+
Task-Id: ${taskId}`;
|
|
1620
1629
|
|
|
1621
1630
|
if (prUrl) {
|
|
1622
1631
|
if (!shouldAutoCreatePr) {
|
|
@@ -1630,7 +1639,7 @@ Do the requested work, but stop with local changes ready for review.
|
|
|
1630
1639
|
Important:
|
|
1631
1640
|
- Do NOT create new commits, push to the branch, or update the pull request unless the user explicitly asks.
|
|
1632
1641
|
- Do NOT create a new branch or a new pull request.
|
|
1633
|
-
${
|
|
1642
|
+
${signedCommitInstructions}
|
|
1634
1643
|
`;
|
|
1635
1644
|
}
|
|
1636
1645
|
|
|
@@ -1641,9 +1650,8 @@ This task already has an open pull request: ${prUrl}
|
|
|
1641
1650
|
|
|
1642
1651
|
After completing the requested changes:
|
|
1643
1652
|
1. Check out the existing PR branch with \`gh pr checkout ${prUrl}\`
|
|
1644
|
-
2. Stage
|
|
1645
|
-
3.
|
|
1646
|
-
4. For every PR review comment or review thread you addressed, treat the thread as done only after BOTH of these:
|
|
1653
|
+
2. Stage your changes with \`git add\`, then call the \`git_signed_commit\` tool with a clear \`message\` (do NOT use \`git commit\`/\`git push\` — they are blocked). This commits to the existing PR branch.
|
|
1654
|
+
3. For every PR review comment or review thread you addressed, treat the thread as done only after BOTH of these:
|
|
1647
1655
|
- Reply on the thread with a short note describing what changed (reference the commit SHA when useful) using \`gh api -X POST /repos/{owner}/{repo}/pulls/{n}/comments/{id}/replies -f body='...'\`.
|
|
1648
1656
|
- Resolve the thread via the \`resolveReviewThread\` GraphQL mutation: \`gh api graphql -f query='mutation($id:ID!){resolveReviewThread(input:{threadId:$id}){thread{isResolved}}}' -f id="<thread-node-id>"\`.
|
|
1649
1657
|
List unresolved threads first with \`gh api graphql -f query='{repository(owner:"<owner>",name:"<repo>"){pullRequest(number:<n>){reviewThreads(first:100){nodes{id isResolved comments(first:1){nodes{body}}}}}}}'\` so you can resolve each one you fixed.
|
|
@@ -1651,7 +1659,7 @@ After completing the requested changes:
|
|
|
1651
1659
|
Important:
|
|
1652
1660
|
- Do NOT create a new branch or a new pull request.
|
|
1653
1661
|
- Do NOT push fixes for review comments without replying to and resolving each related thread.
|
|
1654
|
-
${
|
|
1662
|
+
${signedCommitInstructions}
|
|
1655
1663
|
`;
|
|
1656
1664
|
}
|
|
1657
1665
|
|
|
@@ -1666,7 +1674,7 @@ When the user asks for code changes:
|
|
|
1666
1674
|
When the user explicitly asks to clone or work in a GitHub repository:
|
|
1667
1675
|
- Clone the repository into /tmp/workspace/repos/<owner>/<repo> using \`gh repo clone <owner>/<repo> /tmp/workspace/repos/<owner>/<repo>\`
|
|
1668
1676
|
- Work from inside that cloned repository for follow-up code changes
|
|
1669
|
-
- If the user explicitly asks you to open or update a pull request, create a branch, commit the
|
|
1677
|
+
- If the user explicitly asks you to open or update a pull request, create a branch, stage your changes with \`git add\` and commit them with the \`git_signed_commit\` tool (do NOT use \`git commit\`/\`git push\` — they are blocked), and open a draft pull request from inside the clone. Before opening the PR, check the cloned repo for a PR template at \`.github/pull_request_template.md\` (or variants; fall back to the org's \`.github\` repo via \`gh api\`) and use it as the body structure, and search for matching open issues with \`gh issue list --search\` to include \`Closes #<n>\` / \`Refs #<n>\` links.
|
|
1670
1678
|
- Do NOT create branches, commits, push changes, or open pull requests unless the user explicitly asks for that`;
|
|
1671
1679
|
|
|
1672
1680
|
return `
|
|
@@ -1686,7 +1694,7 @@ ${publishInstructions}
|
|
|
1686
1694
|
|
|
1687
1695
|
Important:
|
|
1688
1696
|
- Prefer using MCP tools to answer questions with real data over giving generic advice.
|
|
1689
|
-
${
|
|
1697
|
+
${signedCommitInstructions}
|
|
1690
1698
|
`;
|
|
1691
1699
|
}
|
|
1692
1700
|
|
|
@@ -1698,7 +1706,7 @@ Do the requested work, but stop with local changes ready for review.
|
|
|
1698
1706
|
|
|
1699
1707
|
Important:
|
|
1700
1708
|
- Do NOT create a branch, commit, push, or open a pull request unless the user explicitly asks.
|
|
1701
|
-
${
|
|
1709
|
+
${signedCommitInstructions}
|
|
1702
1710
|
`;
|
|
1703
1711
|
}
|
|
1704
1712
|
|
|
@@ -1706,14 +1714,13 @@ ${attributionInstructions}
|
|
|
1706
1714
|
# Cloud Task Execution
|
|
1707
1715
|
|
|
1708
1716
|
After completing the requested changes:
|
|
1709
|
-
1.
|
|
1710
|
-
2. Stage
|
|
1711
|
-
3.
|
|
1712
|
-
4. Before opening the PR, prepare the body:
|
|
1717
|
+
1. Pick a new branch name prefixed with \`posthog-code/\` (e.g. \`posthog-code/fix-login-redirect\`)
|
|
1718
|
+
2. Stage your changes with \`git add\`, then call the \`git_signed_commit\` tool with \`branch\` set to that name and a clear \`message\` (do NOT use \`git commit\`/\`git push\` — they are blocked). The tool creates the branch on the remote and a signed commit on it.
|
|
1719
|
+
3. Before opening the PR, prepare the body:
|
|
1713
1720
|
- Check the repo for a PR template at \`.github/pull_request_template.md\` (also try \`.github/PULL_REQUEST_TEMPLATE.md\`, \`docs/pull_request_template.md\`, and root variants). If one exists, use its exact section headings as the PR body — do NOT fall back to a generic Summary/Test plan format.
|
|
1714
1721
|
- If no repo-level template exists, check the org's \`.github\` repo via \`gh api /repos/<owner>/.github/contents/.github/pull_request_template.md\` (and other common paths) and use that as a fallback.
|
|
1715
1722
|
- Search for matching open issues with \`gh issue list --state open --search '<keywords>'\` (derive keywords from the branch name, commits, and changed files; \`gh issue view <n>\` to confirm relevance). For every issue this PR would resolve, include a \`Closes #<n>\` line in the body so GitHub auto-links and auto-closes it on merge. For issues that are related but not fully resolved, use \`Refs #<n>\` instead.
|
|
1716
|
-
|
|
1723
|
+
4. Create a draft pull request using \`gh pr create --draft${this.config.baseBranch ? ` --base ${this.config.baseBranch}` : ""}\` with a descriptive title and the body prepared above. Add the following footer at the end of the PR description:
|
|
1717
1724
|
\`\`\`
|
|
1718
1725
|
---
|
|
1719
1726
|
*Created with [PostHog Code](https://posthog.com/code?ref=pr)*
|
|
@@ -1721,7 +1728,7 @@ After completing the requested changes:
|
|
|
1721
1728
|
|
|
1722
1729
|
Important:
|
|
1723
1730
|
- Always create the PR as a draft. Do not ask for confirmation.
|
|
1724
|
-
${
|
|
1731
|
+
${signedCommitInstructions}
|
|
1725
1732
|
`;
|
|
1726
1733
|
}
|
|
1727
1734
|
|
|
@@ -1804,18 +1811,35 @@ ${attributionInstructions}
|
|
|
1804
1811
|
|
|
1805
1812
|
private configureEnvironment({
|
|
1806
1813
|
isInternal = false,
|
|
1814
|
+
originProduct,
|
|
1815
|
+
taskId,
|
|
1816
|
+
taskRunId,
|
|
1817
|
+
taskUserId,
|
|
1807
1818
|
}: {
|
|
1808
1819
|
isInternal?: boolean;
|
|
1820
|
+
originProduct?: string | null;
|
|
1821
|
+
taskId?: string | null;
|
|
1822
|
+
taskRunId?: string | null;
|
|
1823
|
+
taskUserId?: number | null;
|
|
1809
1824
|
} = {}): void {
|
|
1810
1825
|
const { apiKey, apiUrl, projectId } = this.config;
|
|
1811
|
-
const product
|
|
1812
|
-
? "background_agents"
|
|
1813
|
-
: "posthog_code";
|
|
1826
|
+
const product = resolveGatewayProduct({ isInternal, originProduct });
|
|
1814
1827
|
const gatewayUrl =
|
|
1815
1828
|
process.env.LLM_GATEWAY_URL || getLlmGatewayUrl(apiUrl, product);
|
|
1816
1829
|
const openaiBaseUrl = gatewayUrl.endsWith("/v1")
|
|
1817
1830
|
? gatewayUrl
|
|
1818
1831
|
: `${gatewayUrl}/v1`;
|
|
1832
|
+
// Forward task metadata as `x-posthog-property-*` headers so the gateway
|
|
1833
|
+
// lifts them onto the $ai_generation event. Routes through the Anthropic
|
|
1834
|
+
// SDK's ANTHROPIC_CUSTOM_HEADERS env var; the OpenAI/codex path has no
|
|
1835
|
+
// equivalent today.
|
|
1836
|
+
const customHeaders = buildGatewayPropertyHeaders({
|
|
1837
|
+
task_origin_product: originProduct,
|
|
1838
|
+
task_internal: isInternal,
|
|
1839
|
+
task_id: taskId,
|
|
1840
|
+
task_run_id: taskRunId,
|
|
1841
|
+
task_user_id: taskUserId,
|
|
1842
|
+
});
|
|
1819
1843
|
|
|
1820
1844
|
Object.assign(process.env, {
|
|
1821
1845
|
// PostHog
|
|
@@ -1828,6 +1852,7 @@ ${attributionInstructions}
|
|
|
1828
1852
|
ANTHROPIC_API_KEY: apiKey,
|
|
1829
1853
|
ANTHROPIC_AUTH_TOKEN: apiKey,
|
|
1830
1854
|
ANTHROPIC_BASE_URL: gatewayUrl,
|
|
1855
|
+
ANTHROPIC_CUSTOM_HEADERS: customHeaders,
|
|
1831
1856
|
// OpenAI (for models like GPT-4, o1, etc.)
|
|
1832
1857
|
OPENAI_API_KEY: apiKey,
|
|
1833
1858
|
OPENAI_BASE_URL: openaiBaseUrl,
|
package/src/types.ts
CHANGED
|
@@ -37,7 +37,8 @@ export interface Task {
|
|
|
37
37
|
| "eval_clusters"
|
|
38
38
|
| "user_created"
|
|
39
39
|
| "support_queue"
|
|
40
|
-
| "session_summaries"
|
|
40
|
+
| "session_summaries"
|
|
41
|
+
| "signal_report";
|
|
41
42
|
github_integration?: number | null;
|
|
42
43
|
repository: string; // Format: "organization/repository" (e.g., "posthog/posthog-js")
|
|
43
44
|
json_schema?: Record<string, unknown> | null; // JSON schema for task output validation
|
package/src/utils/common.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readGithubTokenFromEnv } from "@posthog/git/signed-commit";
|
|
1
2
|
import type { Logger } from "./logger";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -25,6 +26,19 @@ export const IS_ROOT =
|
|
|
25
26
|
|
|
26
27
|
export const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;
|
|
27
28
|
|
|
29
|
+
/**
|
|
30
|
+
* A cloud sandbox run, as opposed to a local desktop session. Cloud sandboxes
|
|
31
|
+
* always set IS_SANDBOX and carry a taskRunId; desktop sessions have neither.
|
|
32
|
+
*/
|
|
33
|
+
export function isCloudRun(meta: { taskRunId?: string } | undefined): boolean {
|
|
34
|
+
return !!process.env.IS_SANDBOX || !!meta?.taskRunId;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** The GitHub token available to the sandbox, if any. */
|
|
38
|
+
export function resolveGithubToken(): string | undefined {
|
|
39
|
+
return readGithubTokenFromEnv();
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
export function unreachable(value: never, logger: Logger): void {
|
|
29
43
|
let valueAsString: string;
|
|
30
44
|
try {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildGatewayPropertyHeaders, resolveGatewayProduct } from "./gateway";
|
|
3
|
+
|
|
4
|
+
describe("resolveGatewayProduct", () => {
|
|
5
|
+
it.each([
|
|
6
|
+
{ isInternal: false, originProduct: undefined, expected: "posthog_code" },
|
|
7
|
+
{
|
|
8
|
+
isInternal: undefined,
|
|
9
|
+
originProduct: undefined,
|
|
10
|
+
expected: "posthog_code",
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
isInternal: false,
|
|
14
|
+
originProduct: "signal_report",
|
|
15
|
+
expected: "posthog_code",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
isInternal: true,
|
|
19
|
+
originProduct: undefined,
|
|
20
|
+
expected: "background_agents",
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
isInternal: true,
|
|
24
|
+
originProduct: "session_summaries",
|
|
25
|
+
expected: "background_agents",
|
|
26
|
+
},
|
|
27
|
+
{ isInternal: true, originProduct: "signal_report", expected: "signals" },
|
|
28
|
+
] as const)(
|
|
29
|
+
"isInternal=$isInternal originProduct=$originProduct -> $expected",
|
|
30
|
+
({ isInternal, originProduct, expected }) => {
|
|
31
|
+
expect(resolveGatewayProduct({ isInternal, originProduct })).toBe(
|
|
32
|
+
expected,
|
|
33
|
+
);
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
describe("buildGatewayPropertyHeaders", () => {
|
|
39
|
+
it("renders each property as an x-posthog-property header line", () => {
|
|
40
|
+
expect(
|
|
41
|
+
buildGatewayPropertyHeaders({
|
|
42
|
+
task_origin_product: "signal_report",
|
|
43
|
+
task_internal: true,
|
|
44
|
+
}),
|
|
45
|
+
).toBe(
|
|
46
|
+
"x-posthog-property-task_origin_product: signal_report\nx-posthog-property-task_internal: true",
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("drops null and undefined values but keeps falsy primitives", () => {
|
|
51
|
+
expect(
|
|
52
|
+
buildGatewayPropertyHeaders({
|
|
53
|
+
task_origin_product: null,
|
|
54
|
+
task_internal: false,
|
|
55
|
+
task_count: 0,
|
|
56
|
+
}),
|
|
57
|
+
).toBe(
|
|
58
|
+
"x-posthog-property-task_internal: false\nx-posthog-property-task_count: 0",
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("returns an empty string when no usable properties remain", () => {
|
|
63
|
+
expect(
|
|
64
|
+
buildGatewayPropertyHeaders({
|
|
65
|
+
task_origin_product: null,
|
|
66
|
+
task_internal: undefined,
|
|
67
|
+
}),
|
|
68
|
+
).toBe("");
|
|
69
|
+
});
|
|
70
|
+
});
|
package/src/utils/gateway.ts
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
|
-
export type GatewayProduct = "posthog_code" | "background_agents";
|
|
1
|
+
export type GatewayProduct = "posthog_code" | "background_agents" | "signals";
|
|
2
|
+
|
|
3
|
+
export function resolveGatewayProduct({
|
|
4
|
+
isInternal,
|
|
5
|
+
originProduct,
|
|
6
|
+
}: {
|
|
7
|
+
isInternal?: boolean;
|
|
8
|
+
originProduct?: string | null;
|
|
9
|
+
} = {}): GatewayProduct {
|
|
10
|
+
if (isInternal) {
|
|
11
|
+
return originProduct === "signal_report" ? "signals" : "background_agents";
|
|
12
|
+
}
|
|
13
|
+
return "posthog_code";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Build `x-posthog-property-<name>: <value>` header lines that the LLM
|
|
18
|
+
* gateway lifts onto the `$ai_generation` event it captures for each call
|
|
19
|
+
* (see `services/llm-gateway/src/llm_gateway/request_context.py`).
|
|
20
|
+
*
|
|
21
|
+
* Returns a newline-joined string ready for `ANTHROPIC_CUSTOM_HEADERS`.
|
|
22
|
+
* `null`/`undefined` property values are dropped.
|
|
23
|
+
*/
|
|
24
|
+
export function buildGatewayPropertyHeaders(
|
|
25
|
+
properties: Record<string, string | number | boolean | null | undefined>,
|
|
26
|
+
): string {
|
|
27
|
+
return Object.entries(properties)
|
|
28
|
+
.filter(([, value]) => value !== null && value !== undefined)
|
|
29
|
+
.map(([key, value]) => `x-posthog-property-${key}: ${value}`)
|
|
30
|
+
.join("\n");
|
|
31
|
+
}
|
|
2
32
|
|
|
3
33
|
function getGatewayBaseUrl(posthogHost: string): string {
|
|
4
34
|
const url = new URL(posthogHost);
|