Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
471 changes: 471 additions & 0 deletions specs/resource-instances.md

Large diffs are not rendered by default.

20 changes: 13 additions & 7 deletions src/client/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import type {
NormalizedPrompt,
PromptID,
PromptRef,
RunResources,
SSEData,
} from "../shared/types";
import { getAgentCommand, getAgents, renamePrompt } from "./api";
Expand Down Expand Up @@ -182,7 +183,7 @@ function flashPane(paneId: string) {
block: "nearest",
inline: "nearest",
});
// Restart-safe, as in `SourceRow.tsx`'s `scrollToRow`: removing the class
// Restart-safe, as in `ResourcesSection.tsx`'s `scrollToInstance`: removing the class
// and forcing a reflow before adding it back makes a repeat click flash
// again instead of no-op-ing into an animation already in flight.
el.classList.remove("pane-flash");
Expand Down Expand Up @@ -783,12 +784,17 @@ function App() {
const current = findPrompt(recorded);
const fill =
current && hasRecordedInputs(recorded)
? panelFill(fromTrace(recorded, current), current, {
type: "trace",
description: `trace ${traceId.slice(0, 8)}…`,
providerId: traceProviderId,
traceId,
})
? panelFill(
fromTrace(recorded, current),
current,
{
type: "trace",
description: `trace ${traceId.slice(0, 8)}…`,
providerId: traceProviderId,
traceId,
},
recorded.resources as RunResources | undefined,
)
: undefined;
// At the variation the run applied, else the version it ran against —
// the server opens head when that version is what's on disk now.
Expand Down
2 changes: 1 addition & 1 deletion src/client/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -665,7 +665,7 @@ export async function deleteDataset(
export async function addDatasetRows(
providerId: string,
datasetId: string,
rows: Pick<DatasetRow, "cells" | "source">[],
rows: Pick<DatasetRow, "cells" | "source" | "resources">[],
): Promise<DatasetRow[]> {
const res = await fetch(datasetUrl(providerId, datasetId, "/rows"), {
method: "POST",
Expand Down
10 changes: 9 additions & 1 deletion src/client/components/AddToDatasetMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import type {
DatasetRowSource,
DatasetSummary,
PromptID,
RunResources,
} from "../../shared/types";
import {
addDatasetRows,
Expand All @@ -25,6 +26,7 @@ import {
import {
countMatches,
type NamedInputs,
rowResources,
type SkippedInput,
toCells,
} from "./named-inputs";
Expand All @@ -34,6 +36,8 @@ import { useAnchoredPopover } from "./use-anchored-popover";
interface Props {
/** What would be added — one row's worth. */
inputs: NamedInputs;
/** The resource instances `inputs` may reference, kept on the row. */
resources?: RunResources;
/** The schema "New dataset…" creates. */
newDatasetFields: Omit<DatasetField, "id">[];
/**
Expand Down Expand Up @@ -86,6 +90,7 @@ function describeSkipped(skipped: SkippedInput[]): string {
*/
export function AddToDatasetMenu({
inputs,
resources,
newDatasetFields,
prompt,
source,
Expand Down Expand Up @@ -150,7 +155,10 @@ export function AddToDatasetMenu({
fields: readonly DatasetField[],
) => {
const { cells, skipped } = toCells(inputs, fields);
await addDatasetRows(target.providerId, target.id, [{ cells, source }]);
const kept = rowResources(resources);
await addDatasetRows(target.providerId, target.id, [
{ cells, source, ...(kept && { resources: kept }) },
]);
setOutcome({
ok: true,
message: `Added to ${target.name}${describeSkipped(skipped)}`,
Expand Down
19 changes: 5 additions & 14 deletions src/client/components/CombinedInputEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { CombinedSelection, FieldGroup } from "./combined-inputs";
import { memberCount } from "./combined-inputs";
import { ExecutionInputEditor } from "./ExecutionInputEditor";
import type { SlotSelection } from "./execution-input-state";
import { nestedField, type ResourceArgsContext } from "./resource-args-context";
import type { SourceContext } from "./source-context";

interface Props {
/** The fan-out slot itself (e.g. `toolsContext`). */
Expand All @@ -28,8 +28,8 @@ interface Props {
* edit to that row.
*/
overwritten?: Record<string, string[]>;
/** Forwarded to each row's {@link ExecutionInputEditor} unchanged — a chip with an argument form under it is still a chip. */
argsContext?: ResourceArgsContext;
/** Forwarded to each row's {@link ExecutionInputEditor} unchanged. */
context?: SourceContext;
}

/**
Expand All @@ -46,7 +46,7 @@ export function CombinedInputEditor({
resources,
slots,
overwritten,
argsContext,
context,
}: Props) {
const totalMembers = memberCount(groups);

Expand Down Expand Up @@ -98,16 +98,7 @@ export function CombinedInputEditor({
}
resources={resources}
slots={rowSlots(slots, propDef.name, group)}
// The row's identity for claiming an argument form (§I) has to
// agree with `computeClaims`, which only ever sees the
// *expanded* selection — so this uses the same representative
// member `rowSlots`/`droppedCandidates` already privilege,
// rather than the group's own synthetic name, which no
// expanded path actually has.
argsContext={
argsContext &&
nestedField(argsContext, `${group.members[0]}.${group.name}`)
}
context={context}
/>
</div>
);
Expand Down
Loading
Loading