Add credential usage field: chat, agent, or any
Credentials now have a usage field ("any", "chat", "agent") so the
same provider can have separate credentials for different use cases.
The Claude OAuth token is tagged "agent" (for Claude Code CLI), while
API keys can be tagged "chat" (for streaming/model listing).
- Add usage column to harness_credentials table
- Add getCredentialsForUsage() that prefers exact match, falls back to "any"
- Chat route and model-providers use chat credentials
- Agent env builder uses agent credentials
- Credentials API accepts usage field on create/update
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { NextRequest } from "next/server";
|
||||
import { z } from "zod";
|
||||
import { getRawCredentialsByProvider, Provider } from "@/lib/credentials";
|
||||
import { getCredentialsForUsage, Provider } from "@/lib/credentials";
|
||||
import { executeChatToolCall, chatToolsAsAnthropic, chatToolsAsOpenAI } from "@/lib/chat-tools";
|
||||
import {
|
||||
streamAnthropic,
|
||||
@@ -78,7 +78,7 @@ export async function POST(request: NextRequest) {
|
||||
const { model, provider, projectId, conversationId } = body;
|
||||
|
||||
// Look up credentials
|
||||
const creds = await getRawCredentialsByProvider(provider as Provider);
|
||||
const creds = await getCredentialsForUsage(provider as Provider, "chat");
|
||||
if (creds.length === 0) {
|
||||
return Response.json(
|
||||
{ error: `No credentials configured for provider: ${provider}` },
|
||||
|
||||
@@ -42,6 +42,7 @@ export async function POST(request: NextRequest) {
|
||||
label: body.label,
|
||||
token: body.token,
|
||||
baseUrl: body.baseUrl,
|
||||
usage: body.usage || "any",
|
||||
};
|
||||
|
||||
const saved = await upsertCredential(cred);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AgentConfig, AGENT_RUNTIMES } from "./agents";
|
||||
import { getRawCredentialsByProvider, Provider } from "./credentials";
|
||||
import { getCredentialsForUsage, getRawCredentialsByProvider, Provider } from "./credentials";
|
||||
|
||||
const PROVIDER_ENV_VARS: Record<string, string> = {
|
||||
anthropic: "ANTHROPIC_API_KEY",
|
||||
@@ -28,7 +28,7 @@ export async function buildAgentEnv(
|
||||
for (const provider of providersToInject) {
|
||||
const envVar = PROVIDER_ENV_VARS[provider];
|
||||
if (!envVar) continue;
|
||||
const creds = await getRawCredentialsByProvider(provider as Provider);
|
||||
const creds = await getCredentialsForUsage(provider as Provider, "agent");
|
||||
if (creds.length > 0) {
|
||||
env[envVar] = creds[0].token;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ async function loadCredentialsFromEnv() {
|
||||
if (!token) continue;
|
||||
const existing = await getRawCredentialsByProvider(provider);
|
||||
if (existing.length > 0) continue;
|
||||
await upsertCredential({ id: `env-${provider}`, provider, label, token });
|
||||
await upsertCredential({ id: `env-${provider}`, provider, label, token, usage: "any" });
|
||||
}
|
||||
|
||||
// Always sync Gitea baseUrl from GITEA_URL env var
|
||||
@@ -90,6 +90,7 @@ async function loadClaudeCredentials() {
|
||||
provider: "anthropic",
|
||||
label: `Claude ${raw.claudeAiOauth.subscriptionType || "API"} (mounted)`,
|
||||
token: raw.claudeAiOauth.accessToken,
|
||||
usage: "agent",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
@@ -127,6 +128,7 @@ async function loadOpenCodeCredentials() {
|
||||
provider,
|
||||
label: `${key} (mounted)`,
|
||||
token,
|
||||
usage: "any",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,12 +11,15 @@ export const GIT_PROVIDERS: Provider[] = ["github", "gitlab", "gitea"];
|
||||
export const AI_PROVIDERS: Provider[] = ["anthropic", "openai", "openrouter", "google", "opencode-zen", "opencode-go"];
|
||||
export const INFRA_PROVIDERS: Provider[] = ["postgres-mcp"];
|
||||
|
||||
export type CredentialUsage = "any" | "chat" | "agent";
|
||||
|
||||
export interface Credential {
|
||||
id: string;
|
||||
provider: Provider;
|
||||
label: string;
|
||||
token: string;
|
||||
baseUrl?: string;
|
||||
usage: CredentialUsage;
|
||||
}
|
||||
|
||||
function maskToken(token: string): string {
|
||||
@@ -31,6 +34,7 @@ function rowToCredential(row: typeof credentialsTable.$inferSelect): Credential
|
||||
label: row.label,
|
||||
token: row.token,
|
||||
baseUrl: row.baseUrl ?? undefined,
|
||||
usage: (row.usage as CredentialUsage) || "any",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -62,6 +66,15 @@ export async function getRawCredentialsByProvider(provider: Provider): Promise<C
|
||||
return rows.map(rowToCredential);
|
||||
}
|
||||
|
||||
/** Get credentials for a specific use case. Returns matching usage first, then "any" as fallback. */
|
||||
export async function getCredentialsForUsage(provider: Provider, usage: "chat" | "agent"): Promise<Credential[]> {
|
||||
const all = await getRawCredentialsByProvider(provider);
|
||||
// Prefer exact match, fall back to "any"
|
||||
const exact = all.filter((c) => c.usage === usage);
|
||||
if (exact.length > 0) return exact;
|
||||
return all.filter((c) => c.usage === "any");
|
||||
}
|
||||
|
||||
export async function upsertCredential(cred: Credential): Promise<Credential> {
|
||||
await db.insert(credentialsTable).values({
|
||||
id: cred.id,
|
||||
@@ -69,6 +82,7 @@ export async function upsertCredential(cred: Credential): Promise<Credential> {
|
||||
label: cred.label,
|
||||
token: cred.token,
|
||||
baseUrl: cred.baseUrl,
|
||||
usage: cred.usage || "any",
|
||||
}).onConflictDoUpdate({
|
||||
target: credentialsTable.id,
|
||||
set: {
|
||||
@@ -76,6 +90,7 @@ export async function upsertCredential(cred: Credential): Promise<Credential> {
|
||||
label: cred.label,
|
||||
token: cred.token,
|
||||
baseUrl: cred.baseUrl,
|
||||
usage: cred.usage || "any",
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getRawCredentialsByProvider } from "./credentials";
|
||||
import { getRawCredentialsByProvider, getCredentialsForUsage } from "./credentials";
|
||||
|
||||
export interface ModelInfo {
|
||||
id: string;
|
||||
@@ -94,7 +94,10 @@ export async function fetchAllModels(): Promise<ModelInfo[]> {
|
||||
}
|
||||
|
||||
async function fetchAnthropicModels(): Promise<ModelInfo[]> {
|
||||
const creds = await getRawCredentialsByProvider("anthropic");
|
||||
// Prefer chat credentials (API keys) over agent credentials (OAuth tokens)
|
||||
const chatCreds = await getCredentialsForUsage("anthropic", "chat");
|
||||
const allCreds = await getRawCredentialsByProvider("anthropic");
|
||||
const creds = chatCreds.length > 0 ? chatCreds : allCreds;
|
||||
if (creds.length === 0) return [];
|
||||
|
||||
for (const cred of creds) {
|
||||
|
||||
1
packages/db/drizzle/0005_outgoing_lake.sql
Normal file
1
packages/db/drizzle/0005_outgoing_lake.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE "harness_credentials" ADD COLUMN "usage" text DEFAULT 'any' NOT NULL;
|
||||
824
packages/db/drizzle/meta/0005_snapshot.json
Normal file
824
packages/db/drizzle/meta/0005_snapshot.json
Normal file
@@ -0,0 +1,824 @@
|
||||
{
|
||||
"id": "2ecc8bb5-604b-4c54-89a6-d9e0ff7e88a6",
|
||||
"prevId": "c8c9e029-bf55-4d40-9bd1-f666aee2e08b",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
"public.harness_agent_configs": {
|
||||
"name": "harness_agent_configs",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"runtime": {
|
||||
"name": "runtime",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"model_id": {
|
||||
"name": "model_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"max_tokens": {
|
||||
"name": "max_tokens",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"env": {
|
||||
"name": "env",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_chat_conversations": {
|
||||
"name": "harness_chat_conversations",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"label": {
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"model": {
|
||||
"name": "model",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "''"
|
||||
},
|
||||
"workspace": {
|
||||
"name": "workspace",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"messages": {
|
||||
"name": "messages",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'[]'::jsonb"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_credentials": {
|
||||
"name": "harness_credentials",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"label": {
|
||||
"name": "label",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"token": {
|
||||
"name": "token",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"base_url": {
|
||||
"name": "base_url",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"usage": {
|
||||
"name": "usage",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'any'"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_event_log": {
|
||||
"name": "harness_event_log",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"trigger_id": {
|
||||
"name": "trigger_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"delivery_id": {
|
||||
"name": "delivery_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"event_type": {
|
||||
"name": "event_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"repo": {
|
||||
"name": "repo",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"commit_sha": {
|
||||
"name": "commit_sha",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"branch": {
|
||||
"name": "branch",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'received'"
|
||||
},
|
||||
"task_id": {
|
||||
"name": "task_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"skip_reason": {
|
||||
"name": "skip_reason",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"error": {
|
||||
"name": "error",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"payload": {
|
||||
"name": "payload",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"harness_event_log_delivery_id_unique": {
|
||||
"name": "harness_event_log_delivery_id_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"delivery_id"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_event_triggers": {
|
||||
"name": "harness_event_triggers",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"enabled": {
|
||||
"name": "enabled",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": true
|
||||
},
|
||||
"event_type": {
|
||||
"name": "event_type",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"repo_filter": {
|
||||
"name": "repo_filter",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"state_filter": {
|
||||
"name": "state_filter",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"context_filter": {
|
||||
"name": "context_filter",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"task_template": {
|
||||
"name": "task_template",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"consecutive_failures": {
|
||||
"name": "consecutive_failures",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"max_consecutive_failures": {
|
||||
"name": "max_consecutive_failures",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 3
|
||||
},
|
||||
"disabled_reason": {
|
||||
"name": "disabled_reason",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"webhook_secret": {
|
||||
"name": "webhook_secret",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_iterations": {
|
||||
"name": "harness_iterations",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"task_id": {
|
||||
"name": "task_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"n": {
|
||||
"name": "n",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"diagnosis": {
|
||||
"name": "diagnosis",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"agent_output": {
|
||||
"name": "agent_output",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"evals": {
|
||||
"name": "evals",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"diff_stats": {
|
||||
"name": "diff_stats",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_model_usage": {
|
||||
"name": "harness_model_usage",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"model_id": {
|
||||
"name": "model_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"provider": {
|
||||
"name": "provider",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"task_id": {
|
||||
"name": "task_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"task_slug": {
|
||||
"name": "task_slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"iteration": {
|
||||
"name": "iteration",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"input_tokens": {
|
||||
"name": "input_tokens",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"output_tokens": {
|
||||
"name": "output_tokens",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"duration_ms": {
|
||||
"name": "duration_ms",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"timestamp": {
|
||||
"name": "timestamp",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_orchestrator": {
|
||||
"name": "harness_orchestrator",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true,
|
||||
"default": "'singleton'"
|
||||
},
|
||||
"running": {
|
||||
"name": "running",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"current_task_id": {
|
||||
"name": "current_task_id",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"heartbeat": {
|
||||
"name": "heartbeat",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_projects": {
|
||||
"name": "harness_projects",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"workspaces": {
|
||||
"name": "workspaces",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'[]'::jsonb"
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.harness_tasks": {
|
||||
"name": "harness_tasks",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"slug": {
|
||||
"name": "slug",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"goal": {
|
||||
"name": "goal",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"status": {
|
||||
"name": "status",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'pending'"
|
||||
},
|
||||
"iteration": {
|
||||
"name": "iteration",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 0
|
||||
},
|
||||
"max_iterations": {
|
||||
"name": "max_iterations",
|
||||
"type": "integer",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": 6
|
||||
},
|
||||
"started_at": {
|
||||
"name": "started_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"completed_at": {
|
||||
"name": "completed_at",
|
||||
"type": "bigint",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"project": {
|
||||
"name": "project",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'—'"
|
||||
},
|
||||
"evals": {
|
||||
"name": "evals",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "'{}'::jsonb"
|
||||
},
|
||||
"pr": {
|
||||
"name": "pr",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"cancel_requested": {
|
||||
"name": "cancel_requested",
|
||||
"type": "boolean",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": false
|
||||
},
|
||||
"spec": {
|
||||
"name": "spec",
|
||||
"type": "jsonb",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
},
|
||||
"public.users": {
|
||||
"name": "users",
|
||||
"schema": "",
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "serial",
|
||||
"primaryKey": true,
|
||||
"notNull": true
|
||||
},
|
||||
"email": {
|
||||
"name": "email",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": true
|
||||
},
|
||||
"name": {
|
||||
"name": "name",
|
||||
"type": "text",
|
||||
"primaryKey": false,
|
||||
"notNull": false
|
||||
},
|
||||
"created_at": {
|
||||
"name": "created_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
},
|
||||
"updated_at": {
|
||||
"name": "updated_at",
|
||||
"type": "timestamp",
|
||||
"primaryKey": false,
|
||||
"notNull": true,
|
||||
"default": "now()"
|
||||
}
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {},
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {
|
||||
"users_email_unique": {
|
||||
"name": "users_email_unique",
|
||||
"nullsNotDistinct": false,
|
||||
"columns": [
|
||||
"email"
|
||||
]
|
||||
}
|
||||
},
|
||||
"policies": {},
|
||||
"checkConstraints": {},
|
||||
"isRLSEnabled": false
|
||||
}
|
||||
},
|
||||
"enums": {},
|
||||
"schemas": {},
|
||||
"sequences": {},
|
||||
"roles": {},
|
||||
"policies": {},
|
||||
"views": {},
|
||||
"_meta": {
|
||||
"columns": {},
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,13 @@
|
||||
"when": 1774180634616,
|
||||
"tag": "0004_complete_jack_murdock",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 5,
|
||||
"version": "7",
|
||||
"when": 1774183202832,
|
||||
"tag": "0005_outgoing_lake",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -28,6 +28,7 @@ export const credentials = pgTable("harness_credentials", {
|
||||
label: text("label").notNull(),
|
||||
token: text("token").notNull(),
|
||||
baseUrl: text("base_url"),
|
||||
usage: text("usage").notNull().default("any"), // "any" | "chat" | "agent"
|
||||
createdAt: timestamp("created_at").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user