Skip to content

Commit 2ddb859

Browse files
authored
feat(api): add delegation controls and prompt cache lifetimes (#1272)
## Summary Adds Live delegation controls, prompt cache lifetimes, and agent scheduling tools. ## Changes - Add acknowledgement_delay_ms to Live delegation parameters. - Add optional 30m and 12h TTLs to prompt cache breakpoints, including Responses message inputs. - Add the automations agent tool variant. - Preserve existing agent-tool visitors when encountering automations tools.
1 parent 0ce5f3f commit 2ddb859

125 files changed

Lines changed: 15062 additions & 10680 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.castiron.stats.yml‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
schema_version: 1
2-
generation_id: 13866b42-3537-41d4-9c12-f53214868c28
3-
openapi_spec_hash: 4a02922518092801c43f2526a9ced0f5
4-
openapi_transformed_spec_hash: b577364c156fa7f501df6fef87ae11ed
5-
config_hash: 07f8531f9ff20bc9f5156b5a258c76ff
6-
codegen_sha: e92d3226b583127c9519d4b89e52c20d6c596d0b
7-
codegen_hash: 7afac60a97214c8b2cd5a6684367ee3e19efa7bd30856d197a78779278534669
8-
public_codegen_sha: cf08e5bb49e8c3d1f4eadee5d4b517dd2a06cabc
2+
generation_id: ecf0c665-7b5c-432c-8ca0-d26784190472
3+
openapi_spec_hash: 23f0bfa58ad53fef090bea6a72a05dda
4+
openapi_transformed_spec_hash: c631189d638b72705db583893fa22bb2
5+
config_hash: 249b5f41fe1b916955299cea75cddfbf
6+
codegen_sha: a42b98f1e77a430e69488201ad31243f9a938996
7+
codegen_hash: 36d13008ea00041d76a078918a4b3cac9d4206d4f79cbdd222e65912a347ef33
8+
public_codegen_sha: 4720178859e015fec0cbd3af1e1a7a4244a11434

‎.github/workflows/castiron-custom-code-comment.yml‎

Lines changed: 37 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,21 @@ jobs:
2929
pull-requests: read
3030
statuses: write
3131
steps:
32-
# Trusted main definition: no candidate checkout, artifacts, or executable inputs.
32+
# Execute only the helper belonging to this immutable workflow revision.
33+
- name: Check out the trusted review policy
34+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
35+
with:
36+
ref: ${{ github.workflow_sha }}
37+
persist-credentials: false
38+
3339
- name: Re-evaluate current PR and queue after review changes
40+
env:
41+
GH_TOKEN: ${{ github.token }}
42+
GIT_CONFIG_COUNT: '2'
43+
GIT_CONFIG_KEY_0: credential.helper
44+
GIT_CONFIG_VALUE_0: ''
45+
GIT_CONFIG_KEY_1: credential.https://github.com.helper
46+
GIT_CONFIG_VALUE_1: '!gh auth git-credential'
3447
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
3548
with:
3649
script: |
@@ -56,58 +69,21 @@ jobs:
5669
if (!/^[0-9a-f]{40}$/.test(sha || '')) throw new Error('Invalid policy merge base');
5770
return sha;
5871
}
59-
async function readPolicy(ref) {
60-
const {data: file} = await github.rest.repos.getContent({
61-
...context.repo, path: '.castiron-ratchet.json', ref,
62-
});
63-
if (file.type !== 'file' || file.encoding !== 'base64' || !Number.isSafeInteger(file.size) ||
64-
file.size > 4096 || typeof file.content !== 'string') throw new Error('Invalid policy file');
65-
const content = Buffer.from(file.content, 'base64');
66-
if (content.length !== file.size) throw new Error('Invalid policy content');
67-
const policy = JSON.parse(content.toString('utf8'), (key, value, source) =>
68-
key === 'max_custom_patch_lines' && typeof value === 'number' ? BigInt(source.source) : value);
69-
if (!policy || typeof policy !== 'object' || typeof policy.max_custom_patch_lines !== 'bigint' ||
70-
policy.max_custom_patch_lines < 0n) throw new Error('Invalid policy budget');
71-
return policy;
72-
}
73-
async function supportsEffectivePinReview(ref) {
74-
let file;
72+
async function requiresHuman(pr, mainSha) {
73+
const path = require('node:path');
74+
const fs = require('node:fs');
75+
const root = fs.mkdtempSync(path.join(process.env.RUNNER_TEMP, 'castiron-review-'));
7576
try {
76-
({data: file} = await github.rest.repos.getContent({
77-
...context.repo, path: 'scripts/castiron/custom_code_policy.py', ref,
78-
}));
79-
} catch (error) {
80-
if (error.status === 404) return false;
81-
throw error;
77+
const result = await exec.getExecOutput('python3', ['-I',
78+
'scripts/castiron/custom_code_policy.py', 'review-required',
79+
'--repository', repo, '--repo', path.join(root, 'objects.git'),
80+
'--base', pr.base.sha, '--head', pr.head.sha, '--main', mainSha], {silent: true});
81+
const decision = JSON.parse(result.stdout);
82+
if (typeof decision.requires_human !== 'boolean') throw new Error('Invalid review decision');
83+
return decision.requires_human;
84+
} finally {
85+
fs.rmSync(root, {recursive: true, force: true});
8286
}
83-
if (file.type !== 'file' || file.encoding !== 'base64' || !Number.isSafeInteger(file.size) ||
84-
file.size < 0 || typeof file.content !== 'string') throw new Error('Invalid checker contract');
85-
const content = Buffer.from(file.content, 'base64');
86-
if (content.length !== file.size) throw new Error('Invalid checker content');
87-
// Read data only from the effective checker, never import or execute it.
88-
const declarations = content.toString('utf8').match(/^PIN_REVIEW_POLICY = .*$/gm) || [];
89-
return declarations.length === 1 && declarations[0] === 'PIN_REVIEW_POLICY = "effective-policy-v1"';
90-
}
91-
async function pinRequiresHuman(pr, headPolicy, mainSha) {
92-
const targetPolicy = await readPolicy(pr.base.sha);
93-
const pinSha = pin => pin?.repository === repo && /^[0-9a-f]{40}$/.test(pin.main_sha || '')
94-
? pin.main_sha : null;
95-
const proposedChecker = pinSha(headPolicy.next_policy);
96-
const previousChecker = targetPolicy.next_policy ? pinSha(targetPolicy.next_policy) : mainSha;
97-
if (!proposedChecker || !/^[0-9a-f]{40}$/.test(previousChecker || '') ||
98-
!/^[0-9a-f]{40}$/.test(mainSha || '')) return true;
99-
// Older checkers require human review for every pin edit. Retain that
100-
// requirement until the protected checker explicitly supports the exemption.
101-
if (!await supportsEffectivePinReview(previousChecker)) return true;
102-
const [previous, proposed, previousBase, proposedBase] = await Promise.all([
103-
readPolicy(previousChecker),
104-
readPolicy(proposedChecker), mergeBase(previousChecker, proposedChecker),
105-
mergeBase(proposedChecker, mainSha),
106-
]);
107-
return previousBase !== previousChecker || proposedBase !== proposedChecker ||
108-
proposed.max_custom_patch_lines > previous.max_custom_patch_lines ||
109-
proposed.schema_version !== previous.schema_version ||
110-
proposed.generated_files !== previous.generated_files || proposed.ratchet !== previous.ratchet;
11187
}
11288
const dirtyTargets = new Set();
11389
// Retry discovery within this job timeout while targets are changing.
@@ -146,18 +122,17 @@ jobs:
146122
const pr = matching[0];
147123
const files = await github.paginate(github.rest.pulls.listFiles, {...context.repo, pull_number: pr.number});
148124
if (!files.some(file => file.filename === '.castiron-ratchet.json')) return;
149-
const baseline = await mergeBase(pr.base.sha, pr.head.sha);
150-
const [basePolicy, headPolicy] = await Promise.all([readPolicy(baseline), readPolicy(pr.head.sha)]);
151-
const pinChanged = !require('node:util').isDeepStrictEqual(basePolicy.next_policy ?? null, headPolicy.next_policy ?? null);
152-
let requiresHuman = headPolicy.max_custom_patch_lines > basePolicy.max_custom_patch_lines ||
153-
(headPolicy.ratchet === 'go' && basePolicy.ratchet !== 'go');
154-
let mainSha = null;
155-
if (!requiresHuman && pinChanged) {
156-
const {data: main} = await github.rest.git.getRef({...context.repo, ref: 'heads/main'});
157-
mainSha = main.object.sha;
158-
requiresHuman = await pinRequiresHuman(pr, headPolicy, mainSha);
125+
const {data: main} = await github.rest.git.getRef({...context.repo, ref: 'heads/main'});
126+
const mainSha = main.object.sha;
127+
let requiresReview;
128+
try {
129+
requiresReview = await requiresHuman(pr, mainSha);
130+
} catch (error) {
131+
const {data: currentMain} = await github.rest.git.getRef({...context.repo, ref: 'heads/main'});
132+
if (currentMain.object.sha !== mainSha) continue;
133+
throw error;
159134
}
160-
if (!requiresHuman) {
135+
if (!requiresReview) {
161136
const [{data: current}, {data: target}, main] = await Promise.all([
162137
github.rest.pulls.get({...context.repo, pull_number: pr.number}),
163138
github.rest.git.getRef({...context.repo, ref: 'heads/next'}),

0 commit comments

Comments
 (0)