Files
wehub-resource-sync fed8b2eed7
Build and push multi-arch DocsGPT Docker image / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Backend release / release (push) Has been cancelled
Bandit Security Scan / bandit_scan (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push multi-arch DocsGPT Docker image / manifest (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/amd64, ubuntu-latest, amd64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / build (linux/arm64, ubuntu-24.04-arm, arm64) (push) Has been cancelled
Build and push DocsGPT FE Docker image for development / manifest (push) Has been cancelled
Python linting / ruff (push) Has been cancelled
Run python tests with pytest / Run tests and count coverage (3.12) (push) Has been cancelled
React Widget Build / build (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:28:29 +08:00

115 lines
3.7 KiB
TypeScript

/**
* Shared agent provisioning for specs that need a published agent
* (with a real api_key) for subsequent /stream or /search
* calls. A PUBLISHED classic agent requires name, description, chunks,
* retriever, prompt_id AND a source — otherwise `/api/create_agent`
* returns 400.
*
* Instead of spawning /api/upload (which is Celery-ingestion-dependent
* and orthogonal to what most specs care about), we insert a fixture
* `sources` row directly — the schema is locked by alembic 0001_initial.
* This mirrors the `insertFixtureSource` pattern in agents.spec.ts.
*/
import type { APIRequestContext } from '@playwright/test';
import * as playwright from '@playwright/test';
import { pg } from './db.js';
const API_URL = process.env.API_URL ?? 'http://127.0.0.1:7099';
/**
* Build a multipart-capable APIRequestContext bearing `token`. Does NOT
* set a default Content-Type (unlike `authedRequest`) so Playwright's
* multipart boundary is the only Content-Type Flask sees.
*/
export async function multipartAuthedRequest(
token: string,
): Promise<APIRequestContext> {
return playwright.request.newContext({
baseURL: API_URL,
extraHTTPHeaders: {
Authorization: `Bearer ${token}`,
},
});
}
/**
* Insert a minimal `sources` row owned by `userId`. Matches the DDL in
* application/alembic/versions/0001_initial.py.
*/
export async function insertFixtureSource(
userId: string,
name: string,
): Promise<string> {
const { rows } = await pg.query<{ id: string }>(
`INSERT INTO sources (user_id, name, date, retriever)
VALUES ($1, $2, now(), 'classic')
RETURNING id::text AS id`,
[userId, name],
);
const id = rows[0]?.id;
if (!id) {
throw new Error('insertFixtureSource: no id returned');
}
return id;
}
/**
* Provision a PUBLISHED classic agent end-to-end and return {id, key}.
*
* Creates (1) a fresh `sources` row owned by `userId`, (2) a prompt via
* /api/create_prompt, then (3) a published agent via /api/create_agent
* multipart with all required fields. The returned `key` is the agent's
* api_key — use it in /stream body as `api_key: <key>` to exercise the
* widget/integration path.
*
* Callers MUST pass their own `jsonApi` (for /api/create_prompt) because
* creating a prompt requires a JSON-Content-Type context.
*/
export async function publishClassicAgent(
jsonApi: APIRequestContext,
multipartApi: APIRequestContext,
userId: string,
name: string,
opts: { promptName?: string; promptContent?: string } = {},
): Promise<{ id: string; key: string; sourceId: string; promptId: string }> {
const sourceId = await insertFixtureSource(userId, `${name}-src`);
const promptRes = await jsonApi.post('/api/create_prompt', {
data: {
name: opts.promptName ?? `${name}-prompt`,
content: opts.promptContent ?? 'Be concise.',
},
});
if (promptRes.status() !== 200) {
throw new Error(
`create_prompt failed ${promptRes.status()}: ${await promptRes.text()}`,
);
}
const { id: promptId } = (await promptRes.json()) as { id: string };
const createRes = await multipartApi.post('/api/create_agent', {
multipart: {
name,
description: `e2e agent ${name}`,
status: 'published',
agent_type: 'classic',
chunks: '2',
retriever: 'classic',
prompt_id: promptId,
source: sourceId,
},
});
if (createRes.status() !== 201) {
throw new Error(
`create_agent publish failed ${createRes.status()}: ${await createRes.text()}`,
);
}
const body = (await createRes.json()) as { id: string; key: string };
if (!body.id || !body.key) {
throw new Error(`create_agent returned no id/key: ${JSON.stringify(body)}`);
}
return { id: body.id, key: body.key, sourceId, promptId };
}