From 831719f893aba7ffc4f66a3adf17ee937e2dba1a Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:22:52 +0530 Subject: [PATCH 1/7] init --- .../trueforge/src/runtime/sessionResources.ts | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/packages/trueforge/src/runtime/sessionResources.ts b/packages/trueforge/src/runtime/sessionResources.ts index 9cd1c5450..726dff064 100644 --- a/packages/trueforge/src/runtime/sessionResources.ts +++ b/packages/trueforge/src/runtime/sessionResources.ts @@ -1,4 +1,4 @@ -import type { AgentSpec } from '@truefoundry/trueforge-core/agent-session'; +import type { AgentSpec, SessionHandle } from '@truefoundry/trueforge-core/agent-session'; import { Sandbox, SkillMounter, @@ -28,6 +28,35 @@ export interface McpConnection { headers: RemoteMcpHeaders; } +/** Gateway header carrying stringified JSON metadata. */ +export const X_TFY_METADATA = 'x-tfy-metadata'; + +/** Prefix for harness-owned keys */ +export const TFG_METADATA_PREFIX = 'tfg'; + +/** Caller session.metadata, then stamp `tfg.*` so harness keys always win on collision. */ +export function buildGatewayMetadata(input: { session: SessionHandle; turnId: string }): Record { + const metadata: Record = { ...input.session.metadata }; + metadata[`${TFG_METADATA_PREFIX}.session_id`] = input.session.session_id; + metadata[`${TFG_METADATA_PREFIX}.turn_id`] = input.turnId; + const { agent } = input.session; + if (agent.type === 'reference') { + metadata[`${TFG_METADATA_PREFIX}.agent_id`] = agent.id; + if (agent.name !== null) { + metadata[`${TFG_METADATA_PREFIX}.agent_name`] = agent.name; + } + } + return metadata; +} + +/** Header map for model/MCP gateway calls; empty when metadata has no keys. */ +export function gatewayMetadataHeaders(metadata: Record): Record { + if (Object.keys(metadata).length === 0) { + return {}; + } + return { [X_TFY_METADATA]: JSON.stringify(metadata) }; +} + /** Split `provider/model` FQN. Returns undefined when the shape is not exactly one slash. */ export function parseModelFqn(name: string): { providerName: string; modelName: string } | undefined { const slash = name.indexOf('/'); From bf83adffd29fdb130f1dd4254e0618408fb8b104 Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:31:05 +0530 Subject: [PATCH 2/7] feat: forward session/turn context as x-tfy-metadata on TrueFoundry gateway calls Stamp tfg.session_id, turn_id, and agent fields onto model and MCP invoke headers when TrueFoundry mode is enabled, minting the turn id before the resolver so both paths share one metadata map. Co-authored-by: Cursor --- packages/trueforge/src/apis/turns.ts | 39 ++++++++++++++----- .../trueforge/src/runtime/sessionResources.ts | 24 ++++++++++++ 2 files changed, 53 insertions(+), 10 deletions(-) diff --git a/packages/trueforge/src/apis/turns.ts b/packages/trueforge/src/apis/turns.ts index f362f9b0a..2da5154eb 100644 --- a/packages/trueforge/src/apis/turns.ts +++ b/packages/trueforge/src/apis/turns.ts @@ -32,7 +32,7 @@ import { streamSSE } from 'hono/streaming'; import type { Logger } from 'winston'; import type { Authorizer } from '../auth/authorizer'; import type { ResolveRequestContext } from '../auth/identity'; -import configuration from '../config'; +import configuration, { isTrueFoundryModeEnabled } from '../config'; import type { AgentRecord, IAgentStore } from '../db/agentStore'; import type { IMcpServerWithAuthStore } from '../db/mcpServerStore'; import type { IModelProviderStore } from '../db/modelProviderStore'; @@ -51,10 +51,13 @@ import { StreamGoneError, type EventSubscription, type EventSubscriptionRegistry import { mintPeeredTurnId } from '../runtime/peeringIds'; import { validateSandboxFilePath } from '../runtime/sandboxFilePath'; import { + buildGatewayMetadata, buildTurnSandbox, + gatewayMetadataHeaders, getMcpConnection, getModelDetails, resolveSandboxProvider, + withGatewayMetadataHeaders, } from '../runtime/sessionResources'; import { checkSnapshotStatus } from '../sandbox/providerUtils'; import { canReadAgentBoundResource } from './agentAccess'; @@ -142,9 +145,9 @@ function createTurnResolver(deps: { modelProviderStore: IModelProviderStore; logger: Logger; signal: AbortSignal; - tenant_id: string; userRef: string; - sessionId: string; + session: SessionHandle; + turnId: string; }): TurnResourceResolver { const { mcpServerStore, @@ -154,10 +157,16 @@ function createTurnResolver(deps: { modelProviderStore, logger, signal, - tenant_id, userRef, - sessionId, + session, + turnId, } = deps; + const tenant_id = session.tenant_id; + const sessionId = session.session_id; + const metadataHeaders = isTrueFoundryModeEnabled() + ? gatewayMetadataHeaders(buildGatewayMetadata({ session, turnId })) + : {}; + return new TurnResourceResolver({ llm: async name => { const resolved = await getModelDetails({ @@ -167,7 +176,10 @@ function createTurnResolver(deps: { }); return { modelClient: new VercelAILLM({ - providerConfig: resolved.providerConfig, + providerConfig: { + ...resolved.providerConfig, + headers: { ...resolved.providerConfig.headers, ...metadataHeaders }, + }, logger, signal, }), @@ -187,7 +199,13 @@ function createTurnResolver(deps: { message: `Unknown MCP server "${name}" — not configured`, }); } - return connection; + return { + url: connection.url, + headers: withGatewayMetadataHeaders({ + headers: connection.headers, + metadataHeaders, + }), + }; }, mcpRequestTimeoutMs: configuration.MCP_REQUEST_TIMEOUT_MS, mcpConnectTimeoutMs: configuration.MCP_CONNECT_TIMEOUT_MS, @@ -373,6 +391,7 @@ export async function beginTurnExecution(params: { }): Promise<{ turn: TurnHandle; drainInput: TurnEventDrainInput }> { const { session, input, previous_turn_id: previousTurnId, userRef, deps } = params; const sessionId = session.session_id; + const turnId = mintPeeredTurnId(configuration.EXECUTOR_ID); const abortController = new AbortController(); const tenant_id = session.tenant_id; @@ -384,9 +403,9 @@ export async function beginTurnExecution(params: { modelProviderStore: deps.modelProviderStore, logger: deps.logger, signal: abortController.signal, - tenant_id, userRef, - sessionId, + session, + turnId, }); // First turn only: derive the title from the first user message. The store @@ -394,7 +413,7 @@ export async function beginTurnExecution(params: { const title = session.record.last_turn_id ? undefined : deriveSessionTitle(input); const turn = await session.createTurn({ - turn_id: mintPeeredTurnId(configuration.EXECUTOR_ID), + turn_id: turnId, input, previous_turn_id: previousTurnId, signal: abortController.signal, diff --git a/packages/trueforge/src/runtime/sessionResources.ts b/packages/trueforge/src/runtime/sessionResources.ts index 726dff064..cff42a3d0 100644 --- a/packages/trueforge/src/runtime/sessionResources.ts +++ b/packages/trueforge/src/runtime/sessionResources.ts @@ -57,6 +57,30 @@ export function gatewayMetadataHeaders(metadata: Record): Record return { [X_TFY_METADATA]: JSON.stringify(metadata) }; } +/** + * Merge gateway metadata into MCP invoke headers. Preserves authRequired; + * metadata is applied after auth/per-server headers. + */ +export function withGatewayMetadataHeaders(input: { + headers: RemoteMcpHeaders; + metadataHeaders: Record; +}): RemoteMcpHeaders { + const { headers, metadataHeaders } = input; + if (Object.keys(metadataHeaders).length === 0) { + return headers; + } + if (typeof headers !== 'function') { + return { ...headers, ...metadataHeaders }; + } + return async () => { + const result = await headers(); + if ('authRequired' in result) { + return result; + } + return { headers: { ...result.headers, ...metadataHeaders } }; + }; +} + /** Split `provider/model` FQN. Returns undefined when the shape is not exactly one slash. */ export function parseModelFqn(name: string): { providerName: string; modelName: string } | undefined { const slash = name.indexOf('/'); From 8eb2b08b7bcf215245b7dda1dce18a058e3fc1ec Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:31:54 +0530 Subject: [PATCH 3/7] test: cover gateway metadata helpers and add changeset Co-authored-by: Cursor --- .changeset/gateway-tfy-metadata.md | 5 + .../unit/runtime/sessionResources.test.ts | 138 +++++++++++++++++- 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 .changeset/gateway-tfy-metadata.md diff --git a/.changeset/gateway-tfy-metadata.md b/.changeset/gateway-tfy-metadata.md new file mode 100644 index 000000000..210d0599a --- /dev/null +++ b/.changeset/gateway-tfy-metadata.md @@ -0,0 +1,5 @@ +--- +"@truefoundry/trueforge": patch +--- + +Forward session, turn, and agent context as `x-tfy-metadata` on TrueFoundry-mode model and MCP gateway calls. diff --git a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts index 7c2997a0d..e94428c45 100644 --- a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts +++ b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts @@ -1,4 +1,11 @@ -import { AgentSpecSchema } from '@truefoundry/trueforge-core/agent-session'; +import { + AgentSpecSchema, + InMemorySessionStore, + Sessions, + type SessionAgent, + type SessionHandle, + type SessionMetadata, +} from '@truefoundry/trueforge-core/agent-session'; import { HTTPException } from 'hono/http-exception'; import { validateGitAgentSkills } from '../../../src/db/gitSkillMounts'; import { migrateSqliteToLatest } from '../../../src/db/migrateSqlite'; @@ -8,10 +15,137 @@ import { SqliteMcpServerStore } from '../../../src/db/sqlite/mcp-server-store/Sq import { SqliteModelProviderStore } from '../../../src/db/sqlite/model-provider-store/SqliteModelProviderStore'; import { SqliteSandboxProviderStore } from '../../../src/db/sqlite/sandbox-provider-store/SqliteSandboxProviderStore'; import { SqliteSkillStore } from '../../../src/db/sqlite/skill-store/SqliteSkillStore'; -import { getModelDetails, localSandboxSessionSegment, validateAgentSpec } from '../../../src/runtime/sessionResources'; +import { + buildGatewayMetadata, + gatewayMetadataHeaders, + getModelDetails, + localSandboxSessionSegment, + TFG_METADATA_PREFIX, + validateAgentSpec, + withGatewayMetadataHeaders, + X_TFY_METADATA, +} from '../../../src/runtime/sessionResources'; import { setCachedLocalSandboxSupport } from '../../../src/sandbox/localRuntime'; import type { ReasoningEffort } from '../../../src/schemas/modelProvider'; +async function createGatewayMetadataSession(input: { + agent: SessionAgent; + metadata?: SessionMetadata; +}): Promise { + const sessions = new Sessions({ sessionStore: new InMemorySessionStore() }); + return sessions.create({ + tenant_id: 'tenant-1', + session_id: 'sess-1', + created_by_subject: { subject_id: 'user-1', subject_type: 'user', subject_display_name: 'user-1' }, + agent: input.agent, + metadata: input.metadata ?? {}, + external_id: null, + }); +} + +describe('buildGatewayMetadata', () => { + it('stamps session/turn ids and reference agent fields over session metadata', async () => { + const session = await createGatewayMetadataSession({ + agent: { type: 'reference', id: 'agent-1', name: 'my-agent' }, + metadata: { env: 'dev', [`${TFG_METADATA_PREFIX}.session_id`]: 'caller-override' }, + }); + + expect(buildGatewayMetadata({ session, turnId: 'turn-1' })).toEqual({ + env: 'dev', + [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', + [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-1', + [`${TFG_METADATA_PREFIX}.agent_id`]: 'agent-1', + [`${TFG_METADATA_PREFIX}.agent_name`]: 'my-agent', + }); + }); + + it('omits agent_name when the reference name snapshot is null', async () => { + const session = await createGatewayMetadataSession({ + agent: { type: 'reference', id: 'agent-legacy', name: null }, + }); + + expect(buildGatewayMetadata({ session, turnId: 'turn-2' })).toEqual({ + [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', + [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-2', + [`${TFG_METADATA_PREFIX}.agent_id`]: 'agent-legacy', + }); + }); + + it('omits agent keys for inline agents', async () => { + const session = await createGatewayMetadataSession({ + agent: { + type: 'inline', + spec: AgentSpecSchema.parse({ model: { name: 'openai/gpt-4o' } }), + }, + metadata: { ticket: 'T-1' }, + }); + + expect(buildGatewayMetadata({ session, turnId: 'turn-3' })).toEqual({ + ticket: 'T-1', + [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', + [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-3', + }); + }); +}); + +describe('gatewayMetadataHeaders', () => { + it('stringifies metadata under x-tfy-metadata', () => { + expect(gatewayMetadataHeaders({ a: '1' })).toEqual({ + [X_TFY_METADATA]: JSON.stringify({ a: '1' }), + }); + expect(gatewayMetadataHeaders({})).toEqual({}); + }); +}); + +describe('withGatewayMetadataHeaders', () => { + it('merges into static headers', () => { + const headers = withGatewayMetadataHeaders({ + headers: { Authorization: 'Bearer t' }, + metadataHeaders: { [X_TFY_METADATA]: '{"k":"v"}' }, + }); + expect(headers).toEqual({ + Authorization: 'Bearer t', + [X_TFY_METADATA]: '{"k":"v"}', + }); + }); + + it('merges into async header resolvers and preserves authRequired', async () => { + const withAuth = withGatewayMetadataHeaders({ + headers: async () => ({ headers: { Authorization: 'Bearer t' } }), + metadataHeaders: { [X_TFY_METADATA]: '{"k":"v"}' }, + }); + expect(typeof withAuth).toBe('function'); + if (typeof withAuth !== 'function') { + throw new Error('expected async header resolver'); + } + await expect(withAuth()).resolves.toEqual({ + headers: { + Authorization: 'Bearer t', + [X_TFY_METADATA]: '{"k":"v"}', + }, + }); + + const authRequired = withGatewayMetadataHeaders({ + headers: async () => ({ + authRequired: { servers: [{ id: 'mcp', name: 'mcp', auth_url: 'https://auth.example' }] }, + }), + metadataHeaders: { [X_TFY_METADATA]: '{"k":"v"}' }, + }); + expect(typeof authRequired).toBe('function'); + if (typeof authRequired !== 'function') { + throw new Error('expected async header resolver'); + } + await expect(authRequired()).resolves.toEqual({ + authRequired: { servers: [{ id: 'mcp', name: 'mcp', auth_url: 'https://auth.example' }] }, + }); + }); + + it('returns the original headers when metadata is empty', () => { + const staticHeaders = { Authorization: 'Bearer t' }; + expect(withGatewayMetadataHeaders({ headers: staticHeaders, metadataHeaders: {} })).toBe(staticHeaders); + }); +}); + describe('localSandboxSessionSegment', () => { it('keeps a single-segment session id and rejects missing or unsafe values', () => { expect(localSandboxSessionSegment('sess_1')).toBe('sess_1'); From 046d5cbbdc3cf10d1502514d7f8462b9e78a4c86 Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:34:17 +0530 Subject: [PATCH 4/7] nit --- .../unit/runtime/sessionResources.test.ts | 56 +------------------ 1 file changed, 1 insertion(+), 55 deletions(-) diff --git a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts index e94428c45..8dff30133 100644 --- a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts +++ b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts @@ -17,7 +17,6 @@ import { SqliteSandboxProviderStore } from '../../../src/db/sqlite/sandbox-provi import { SqliteSkillStore } from '../../../src/db/sqlite/skill-store/SqliteSkillStore'; import { buildGatewayMetadata, - gatewayMetadataHeaders, getModelDetails, localSandboxSessionSegment, TFG_METADATA_PREFIX, @@ -44,7 +43,7 @@ async function createGatewayMetadataSession(input: { } describe('buildGatewayMetadata', () => { - it('stamps session/turn ids and reference agent fields over session metadata', async () => { + it('stamps session/turn/agent fields and lets tfg.* win over session metadata', async () => { const session = await createGatewayMetadataSession({ agent: { type: 'reference', id: 'agent-1', name: 'my-agent' }, metadata: { env: 'dev', [`${TFG_METADATA_PREFIX}.session_id`]: 'caller-override' }, @@ -58,57 +57,9 @@ describe('buildGatewayMetadata', () => { [`${TFG_METADATA_PREFIX}.agent_name`]: 'my-agent', }); }); - - it('omits agent_name when the reference name snapshot is null', async () => { - const session = await createGatewayMetadataSession({ - agent: { type: 'reference', id: 'agent-legacy', name: null }, - }); - - expect(buildGatewayMetadata({ session, turnId: 'turn-2' })).toEqual({ - [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', - [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-2', - [`${TFG_METADATA_PREFIX}.agent_id`]: 'agent-legacy', - }); - }); - - it('omits agent keys for inline agents', async () => { - const session = await createGatewayMetadataSession({ - agent: { - type: 'inline', - spec: AgentSpecSchema.parse({ model: { name: 'openai/gpt-4o' } }), - }, - metadata: { ticket: 'T-1' }, - }); - - expect(buildGatewayMetadata({ session, turnId: 'turn-3' })).toEqual({ - ticket: 'T-1', - [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', - [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-3', - }); - }); -}); - -describe('gatewayMetadataHeaders', () => { - it('stringifies metadata under x-tfy-metadata', () => { - expect(gatewayMetadataHeaders({ a: '1' })).toEqual({ - [X_TFY_METADATA]: JSON.stringify({ a: '1' }), - }); - expect(gatewayMetadataHeaders({})).toEqual({}); - }); }); describe('withGatewayMetadataHeaders', () => { - it('merges into static headers', () => { - const headers = withGatewayMetadataHeaders({ - headers: { Authorization: 'Bearer t' }, - metadataHeaders: { [X_TFY_METADATA]: '{"k":"v"}' }, - }); - expect(headers).toEqual({ - Authorization: 'Bearer t', - [X_TFY_METADATA]: '{"k":"v"}', - }); - }); - it('merges into async header resolvers and preserves authRequired', async () => { const withAuth = withGatewayMetadataHeaders({ headers: async () => ({ headers: { Authorization: 'Bearer t' } }), @@ -139,11 +90,6 @@ describe('withGatewayMetadataHeaders', () => { authRequired: { servers: [{ id: 'mcp', name: 'mcp', auth_url: 'https://auth.example' }] }, }); }); - - it('returns the original headers when metadata is empty', () => { - const staticHeaders = { Authorization: 'Bearer t' }; - expect(withGatewayMetadataHeaders({ headers: staticHeaders, metadataHeaders: {} })).toBe(staticHeaders); - }); }); describe('localSandboxSessionSegment', () => { From 60687a18d50d474bb71f94c7e3dbb6049bf2d493 Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:36:01 +0530 Subject: [PATCH 5/7] nit --- packages/trueforge/src/runtime/sessionResources.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/trueforge/src/runtime/sessionResources.ts b/packages/trueforge/src/runtime/sessionResources.ts index cff42a3d0..71f66d5a8 100644 --- a/packages/trueforge/src/runtime/sessionResources.ts +++ b/packages/trueforge/src/runtime/sessionResources.ts @@ -34,7 +34,6 @@ export const X_TFY_METADATA = 'x-tfy-metadata'; /** Prefix for harness-owned keys */ export const TFG_METADATA_PREFIX = 'tfg'; -/** Caller session.metadata, then stamp `tfg.*` so harness keys always win on collision. */ export function buildGatewayMetadata(input: { session: SessionHandle; turnId: string }): Record { const metadata: Record = { ...input.session.metadata }; metadata[`${TFG_METADATA_PREFIX}.session_id`] = input.session.session_id; From 6debaf769a37b352977bb852c87b23b45dd8b7a2 Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Thu, 10 Sep 2026 19:36:26 +0530 Subject: [PATCH 6/7] nit --- packages/trueforge/src/runtime/sessionResources.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/trueforge/src/runtime/sessionResources.ts b/packages/trueforge/src/runtime/sessionResources.ts index 71f66d5a8..7a88dc245 100644 --- a/packages/trueforge/src/runtime/sessionResources.ts +++ b/packages/trueforge/src/runtime/sessionResources.ts @@ -48,7 +48,6 @@ export function buildGatewayMetadata(input: { session: SessionHandle; turnId: st return metadata; } -/** Header map for model/MCP gateway calls; empty when metadata has no keys. */ export function gatewayMetadataHeaders(metadata: Record): Record { if (Object.keys(metadata).length === 0) { return {}; From d1bf4edc3c52f260ad8caac7704356168ac18473 Mon Sep 17 00:00:00 2001 From: Srajan Asthana Date: Fri, 11 Sep 2026 14:35:21 +0530 Subject: [PATCH 7/7] nit --- packages/trueforge/src/runtime/sessionResources.ts | 8 +++++--- .../tests/unit/runtime/sessionResources.test.ts | 12 +++--------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/trueforge/src/runtime/sessionResources.ts b/packages/trueforge/src/runtime/sessionResources.ts index 7a88dc245..57ef96ea2 100644 --- a/packages/trueforge/src/runtime/sessionResources.ts +++ b/packages/trueforge/src/runtime/sessionResources.ts @@ -35,9 +35,11 @@ export const X_TFY_METADATA = 'x-tfy-metadata'; export const TFG_METADATA_PREFIX = 'tfg'; export function buildGatewayMetadata(input: { session: SessionHandle; turnId: string }): Record { - const metadata: Record = { ...input.session.metadata }; - metadata[`${TFG_METADATA_PREFIX}.session_id`] = input.session.session_id; - metadata[`${TFG_METADATA_PREFIX}.turn_id`] = input.turnId; + // Session.metadata is intentionally omitted for now (Unicode-in-header risk); re-add later. + const metadata: Record = { + [`${TFG_METADATA_PREFIX}.session_id`]: input.session.session_id, + [`${TFG_METADATA_PREFIX}.turn_id`]: input.turnId, + }; const { agent } = input.session; if (agent.type === 'reference') { metadata[`${TFG_METADATA_PREFIX}.agent_id`] = agent.id; diff --git a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts index 8dff30133..9bf1c2566 100644 --- a/packages/trueforge/tests/unit/runtime/sessionResources.test.ts +++ b/packages/trueforge/tests/unit/runtime/sessionResources.test.ts @@ -4,7 +4,6 @@ import { Sessions, type SessionAgent, type SessionHandle, - type SessionMetadata, } from '@truefoundry/trueforge-core/agent-session'; import { HTTPException } from 'hono/http-exception'; import { validateGitAgentSkills } from '../../../src/db/gitSkillMounts'; @@ -27,30 +26,25 @@ import { import { setCachedLocalSandboxSupport } from '../../../src/sandbox/localRuntime'; import type { ReasoningEffort } from '../../../src/schemas/modelProvider'; -async function createGatewayMetadataSession(input: { - agent: SessionAgent; - metadata?: SessionMetadata; -}): Promise { +async function createGatewayMetadataSession(input: { agent: SessionAgent }): Promise { const sessions = new Sessions({ sessionStore: new InMemorySessionStore() }); return sessions.create({ tenant_id: 'tenant-1', session_id: 'sess-1', created_by_subject: { subject_id: 'user-1', subject_type: 'user', subject_display_name: 'user-1' }, agent: input.agent, - metadata: input.metadata ?? {}, + metadata: {}, external_id: null, }); } describe('buildGatewayMetadata', () => { - it('stamps session/turn/agent fields and lets tfg.* win over session metadata', async () => { + it('stamps session/turn/agent fields only', async () => { const session = await createGatewayMetadataSession({ agent: { type: 'reference', id: 'agent-1', name: 'my-agent' }, - metadata: { env: 'dev', [`${TFG_METADATA_PREFIX}.session_id`]: 'caller-override' }, }); expect(buildGatewayMetadata({ session, turnId: 'turn-1' })).toEqual({ - env: 'dev', [`${TFG_METADATA_PREFIX}.session_id`]: 'sess-1', [`${TFG_METADATA_PREFIX}.turn_id`]: 'turn-1', [`${TFG_METADATA_PREFIX}.agent_id`]: 'agent-1',