Repository navigation
Expand file tree
/
Copy pathgithub_action_runtime.ts
More file actions
81 lines (75 loc) · 4.03 KB
/
Copy pathgithub_action_runtime.ts
File metadata and controls
81 lines (75 loc) · 4.03 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import type { AgentProvider, AgentTask, AgentTaskConfiguration } from '../data/model/agent';
import { AgentCliProvisioner } from '../data/repository/agent_cli_provisioner';
import { AgentCliError } from '../data/repository/agent_cli_contracts';
import { OfficialAgentInstallationError } from '../infrastructure/agents/agent_official_installer';
import { runAgentAuthenticationPreflight } from '../data/repository/agent_authentication_preflight';
import { logInfo, logDebugInfo } from '../utils/logger';
import { ApplicationError } from '../application/errors/application_error';
function logProvisioningFailure(provider: AgentProvider, failure: unknown): void {
const diagnostic = failure instanceof OfficialAgentInstallationError
? `official-${failure.stage}${failure.exitCode === undefined ? '' : `-exit-${failure.exitCode}`}`
+ `${failure.reason === undefined ? '' : `-${failure.reason}`}`
: failure instanceof AgentCliError && failure.preflightDiagnostic
? `replacement-trust-${failure.preflightDiagnostic}` : 'unavailable';
logInfo(`Agent runtime ${provider} provisioning failed (${diagnostic}).`);
}
/** Reuses selected agent CLIs, installing missing default CLIs from official sources. */
export function prepareGithubAgentRuntime(
agentTasks: AgentTaskConfiguration,
activeTasks?: readonly AgentTask[],
): void {
const configurations = selectedAgentTasks(agentTasks, activeTasks);
for (const [task, configuration] of configurations) {
const preflight = runAgentAuthenticationPreflight(configuration);
if (preflight.check.status === 'missing' && preflight.shouldFail) {
throw new ApplicationError(
'authorization.credential-invalid',
`Authentication is unavailable for the active ${task} agent role using ${configuration.provider}.`,
);
}
if (preflight.check.status === 'missing' && preflight.mode === 'warn') {
logInfo(`Warning: ${task} agent authentication could not be preflighted: ${preflight.check.message}`);
}
}
if (process.env.GITHUB_ACTIONS === 'true') {
const provisioner = new AgentCliProvisioner();
for (const configuration of uniqueAgentConfigurations(configurations)) {
try {
provisioner.provision(configuration);
} catch (cause) {
logProvisioningFailure(configuration.provider, cause);
throw new ApplicationError(
'configuration.unsupported',
`The ${configuration.provider} runtime is unavailable or its official installation failed.`,
{ cause },
);
}
}
}
logDebugInfo(configurations.length === 0
? 'No agent CLI is required for this event.'
: `Active agent roles: ${configurations.map(([task, configuration]) =>
`${task}=${configuration.provider}/${configuration.modelProvider ?? 'default'}/${configuration.model}`).join(', ')}.`);
}
function configuredAgentTasks(
agentTasks: AgentTaskConfiguration,
): Array<[string, NonNullable<AgentTaskConfiguration[keyof AgentTaskConfiguration]>]> {
return (Object.entries(agentTasks) as Array<[string, NonNullable<AgentTaskConfiguration[keyof AgentTaskConfiguration]>]>)
.filter(([, configuration]) => configuration != null);
}
function selectedAgentTasks(
agentTasks: AgentTaskConfiguration,
activeTasks: readonly AgentTask[] | undefined,
) {
if (!activeTasks) return configuredAgentTasks(agentTasks);
return activeTasks.map((task) => [task, agentTasks[task] ?? agentTasks.findings] as const);
}
function uniqueAgentConfigurations(
configurations: ReadonlyArray<readonly [string, NonNullable<AgentTaskConfiguration[keyof AgentTaskConfiguration]>]>,
) {
const unique = new Map<string, NonNullable<AgentTaskConfiguration[keyof AgentTaskConfiguration]>>();
for (const [, configuration] of configurations) {
unique.set(JSON.stringify(configuration), configuration);
}
return [...unique.values()];
}