-
Notifications
You must be signed in to change notification settings - Fork 52
feat(telemetry): support agent_environment for runtime/harness distinction #1405
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
af15162
6f35946
b67947a
9e70a34
9d84af3
b2f15e1
8063676
d06522a
127a079
7187e11
bbccee9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,10 +9,11 @@ import type { | |
| TargetLanguage, | ||
| } from '../../../schema'; | ||
| import { LIFECYCLE_TIMEOUT_MAX, LIFECYCLE_TIMEOUT_MIN } from '../../../schema'; | ||
| import { ANSI } from '../../constants'; | ||
| import { getErrorMessage } from '../../errors'; | ||
| import { isPreviewEnabled } from '../../feature-flags'; | ||
| import { harnessPrimitive } from '../../primitives/registry'; | ||
| import { runCliCommand } from '../../telemetry/cli-command-run.js'; | ||
| import { runCliCommand, withCommandRunTelemetry } from '../../telemetry/cli-command-run.js'; | ||
| import { | ||
| AgentFramework, | ||
| AgentLanguage, | ||
|
|
@@ -139,78 +140,83 @@ async function handleCreateHarnessCLI(options: CreateOptions): Promise<void> { | |
| const name = options.name ?? options.projectName; | ||
| const projectName = options.projectName ?? name; | ||
|
|
||
| const validation = validateCreateHarnessOptions( | ||
| const result = await withCommandRunTelemetry( | ||
| 'create', | ||
| { | ||
| name, | ||
| projectName, | ||
| modelProvider: options.modelProvider, | ||
| modelId: options.modelId, | ||
| apiKeyArn: options.apiKeyArn, | ||
| agent_environment: 'harness' as const, | ||
| has_agent: true, | ||
| model_provider: standardize(ModelProviderEnum, options.modelProvider ?? 'bedrock'), | ||
| memory_type: standardize(MemoryType, options.harnessMemory === false ? 'none' : 'longandshortterm'), | ||
| network_mode: standardize(NetworkModeEnum, options.networkMode ?? 'public'), | ||
| }, | ||
| cwd | ||
| ); | ||
| if (!validation.valid) { | ||
| if (options.json) { | ||
| console.log(JSON.stringify({ success: false, error: validation.error })); | ||
| } else { | ||
| console.error(validation.error); | ||
| } | ||
| process.exit(1); | ||
| } | ||
| async () => { | ||
| const validation = validateCreateHarnessOptions( | ||
| { | ||
| name, | ||
| projectName, | ||
| modelProvider: options.modelProvider, | ||
| modelId: options.modelId, | ||
| apiKeyArn: options.apiKeyArn, | ||
| }, | ||
| cwd | ||
| ); | ||
| if (!validation.valid) { | ||
| return { success: false as const, error: new ValidationError(validation.error!) }; | ||
| } | ||
|
|
||
| // Progress callback | ||
| const green = '\x1b[32m'; | ||
| const reset = '\x1b[0m'; | ||
| const onProgress: ProgressCallback | undefined = options.json | ||
| ? undefined | ||
| : (step, status) => { | ||
| if (status === 'done') console.log(`${green}[done]${reset} ${step}`); | ||
| else if (status === 'error') console.log(`\x1b[31m[error]${reset} ${step}`); | ||
| }; | ||
| // Progress callback | ||
| const onProgress: ProgressCallback | undefined = options.json | ||
| ? undefined | ||
| : (step, status) => { | ||
| if (status === 'done') console.log(`${ANSI.green}[done]${ANSI.reset} ${step}`); | ||
| else if (status === 'error') console.log(`${ANSI.red}[error]${ANSI.reset} ${step}`); | ||
| }; | ||
|
|
||
| const provider = ( | ||
| options.modelProvider ? normalizeHarnessModelProvider(options.modelProvider) : 'bedrock' | ||
| ) as HarnessModelProvider; | ||
| const defaultModelIds: Record<string, string> = { | ||
| bedrock: 'global.anthropic.claude-sonnet-4-6', | ||
| open_ai: 'gpt-5', | ||
| gemini: 'gemini-2.5-flash', | ||
| }; | ||
| const modelId = options.modelId ?? defaultModelIds[provider] ?? 'global.anthropic.claude-sonnet-4-6'; | ||
|
|
||
| const containerOption = harnessPrimitive!.parseContainerFlag(options.container); | ||
|
|
||
| const result = await createProjectWithHarness({ | ||
| name: name!, | ||
| projectName: projectName!, | ||
| cwd, | ||
| modelProvider: provider, | ||
| modelId, | ||
| apiKeyArn: options.apiKeyArn, | ||
| containerUri: containerOption.containerUri, | ||
| dockerfilePath: containerOption.dockerfilePath, | ||
| skipMemory: options.harnessMemory === false, | ||
| maxIterations: options.maxIterations ? Number(options.maxIterations) : undefined, | ||
| maxTokens: options.maxTokens ? Number(options.maxTokens) : undefined, | ||
| timeoutSeconds: options.timeout ? Number(options.timeout) : undefined, | ||
| truncationStrategy: options.truncationStrategy as 'sliding_window' | 'summarization' | undefined, | ||
| networkMode: options.networkMode as NetworkMode | undefined, | ||
| subnets: parseCommaSeparatedList(options.subnets), | ||
| securityGroups: parseCommaSeparatedList(options.securityGroups), | ||
| idleTimeout: options.idleTimeout ? Number(options.idleTimeout) : undefined, | ||
| maxLifetime: options.maxLifetime ? Number(options.maxLifetime) : undefined, | ||
| sessionStoragePath: options.sessionStorageMountPath, | ||
| skipGit: options.skipGit, | ||
| skipInstall: options.skipInstall, | ||
| onProgress, | ||
| }); | ||
| const provider = ( | ||
| options.modelProvider ? normalizeHarnessModelProvider(options.modelProvider) : 'bedrock' | ||
| ) as HarnessModelProvider; | ||
| const defaultModelIds: Record<string, string> = { | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we should move these constants somewhere else, but OOS here. |
||
| bedrock: 'global.anthropic.claude-sonnet-4-6', | ||
| open_ai: 'gpt-5', | ||
| gemini: 'gemini-2.5-flash', | ||
| }; | ||
| const modelId = options.modelId ?? defaultModelIds[provider] ?? 'global.anthropic.claude-sonnet-4-6'; | ||
|
|
||
| const containerOption = harnessPrimitive!.parseContainerFlag(options.container); | ||
|
|
||
| return createProjectWithHarness({ | ||
| name: name!, | ||
| projectName: projectName!, | ||
| cwd, | ||
| modelProvider: provider, | ||
| modelId, | ||
| apiKeyArn: options.apiKeyArn, | ||
| containerUri: containerOption.containerUri, | ||
| dockerfilePath: containerOption.dockerfilePath, | ||
| skipMemory: options.harnessMemory === false, | ||
| maxIterations: options.maxIterations ? Number(options.maxIterations) : undefined, | ||
| maxTokens: options.maxTokens ? Number(options.maxTokens) : undefined, | ||
| timeoutSeconds: options.timeout ? Number(options.timeout) : undefined, | ||
| truncationStrategy: options.truncationStrategy as 'sliding_window' | 'summarization' | undefined, | ||
| networkMode: options.networkMode as NetworkMode | undefined, | ||
| subnets: parseCommaSeparatedList(options.subnets), | ||
| securityGroups: parseCommaSeparatedList(options.securityGroups), | ||
| idleTimeout: options.idleTimeout ? Number(options.idleTimeout) : undefined, | ||
| maxLifetime: options.maxLifetime ? Number(options.maxLifetime) : undefined, | ||
| sessionStoragePath: options.sessionStorageMountPath, | ||
| skipGit: options.skipGit, | ||
| skipInstall: options.skipInstall, | ||
| onProgress, | ||
| }); | ||
| } | ||
| ); | ||
|
|
||
| if (options.json) { | ||
| console.log(JSON.stringify(result)); | ||
| console.log(JSON.stringify(serializeResult(result))); | ||
| } else if (result.success) { | ||
| printCreateHarnessSummary(projectName!, name!); | ||
| } else { | ||
| console.error(result.error); | ||
| console.error(result.error instanceof Error ? result.error.message : 'Create failed'); | ||
| } | ||
| process.exit(result.success ? 0 : 1); | ||
| } | ||
|
|
@@ -245,6 +251,7 @@ async function handleCreateCLI(options: CreateOptions): Promise<void> { | |
| } | ||
|
|
||
| const knownAttrs = { | ||
| agent_environment: 'runtime' as const, | ||
| agent_language: standardize(AgentLanguage, options.language), | ||
| agent_framework: standardize(AgentFramework, options.framework), | ||
| model_provider: standardize(ModelProviderEnum, options.modelProvider), | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -201,6 +201,7 @@ export const registerDev = (program: Command) => { | |
| const execResult = await withCommandRunTelemetry( | ||
| 'dev', | ||
| { | ||
| agent_environment: 'runtime' as const, | ||
| dev_action: 'exec' as const, | ||
| ui_mode: 'terminal' as const, | ||
| has_stream: false, | ||
|
|
@@ -239,6 +240,7 @@ export const registerDev = (program: Command) => { | |
| const invokeResult = await withCommandRunTelemetry( | ||
| 'dev', | ||
| { | ||
| agent_environment: 'runtime' as const, | ||
| dev_action: 'invoke' as const, | ||
| ui_mode: 'terminal' as const, | ||
| has_stream: opts.stream ?? false, | ||
|
|
@@ -301,6 +303,7 @@ export const registerDev = (program: Command) => { | |
| const serverResult = await withCommandRunTelemetry( | ||
| 'dev', | ||
| { | ||
| agent_environment: 'runtime' as const, | ||
| dev_action: 'server' as const, | ||
| ui_mode: 'terminal' as const, | ||
| has_stream: false, | ||
|
|
@@ -353,6 +356,7 @@ export const registerDev = (program: Command) => { | |
| if (opts.logs) { | ||
| // Preview: harness-only projects need deploy then print invoke instructions | ||
| if (isPreviewEnabled() && supportedAgents.length === 0 && hasHarnesses) { | ||
| recorder.set({ agent_environment: 'harness' as const }); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. harness vs runtime path is dynamic here so we overwrite default attribute when we hit the harness path. |
||
| if (!opts.skipDeploy) { | ||
| await runCliDeploy(); | ||
| } | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See issue for more info, but current behavior is we say "dev not supported on harness" but still exit code 0 which I think is incorrect.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks for cutting the issue! I will look into it